diff options
565 files changed, 9654 insertions, 3287 deletions
diff --git a/Android.bp b/Android.bp index 935b2bb478bb..ee381a42d728 100644 --- a/Android.bp +++ b/Android.bp @@ -1121,6 +1121,7 @@ filegroup { "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 edbd1ae79c48..90df19a9491a 100644 --- a/ApiDocs.bp +++ b/ApiDocs.bp @@ -79,7 +79,7 @@ stubs_defaults { "sdk-dir", "api-versions-jars-dir", ], - previous_api: ":last-released-public-api", + previous_api: ":android.api.public.latest", merge_annotations_dirs: [ "metalava-manual", ], diff --git a/StubLibraries.bp b/StubLibraries.bp index 8fd8c907202c..91efb05b50f4 100644 --- a/StubLibraries.bp +++ b/StubLibraries.bp @@ -58,7 +58,7 @@ stubs_defaults { 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", ], @@ -109,13 +109,13 @@ droidstubs { 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 +151,13 @@ droidstubs { 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 +215,13 @@ droidstubs { 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 +318,7 @@ droidstubs { 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 478cfc1fe811..1b289130124f 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 000000000000..f02cbcfc4daf --- /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 000000000000..7198176f62a0 --- /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 000000000000..69d187f9419a --- /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 index 4ed3b4e09d11..4ed3b4e09d11 100644 --- a/apct-tests/perftests/core/src/android/wm/InternalWindowOperationPerfTest.java +++ b/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 index 836e6b617395..1667c1658a07 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 androidx.test.runner.lifecycle.Stage; 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 @@ public class RecentsAnimationPerfTest extends WindowManagerPerfTestBase { 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 @@ public class RecentsAnimationPerfTest extends WindowManagerPerfTestBase { 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 index 8139a2e963c5..8139a2e963c5 100644 --- a/apct-tests/perftests/core/src/android/wm/RelayoutPerfTest.java +++ b/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 index c72cc9d635e0..c72cc9d635e0 100644 --- a/apct-tests/perftests/core/src/android/wm/WindowAddRemovePerfTest.java +++ b/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 index 9e17e940a06b..9e17e940a06b 100644 --- a/apct-tests/perftests/core/src/android/wm/WindowManagerPerfTestBase.java +++ b/apct-tests/perftests/windowmanager/src/android/wm/WindowManagerPerfTestBase.java diff --git a/apex/Android.bp b/apex/Android.bp index 67cd0d7fcd1e..51e030bd174d 100644 --- a/apex/Android.bp +++ b/apex/Android.bp @@ -74,6 +74,9 @@ stubs_defaults { api_file: "api/current.txt", removed_api_file: "api/removed.txt", }, + api_lint: { + enabled: true, + }, }, dist: { targets: ["sdk", "win_sdk"], @@ -93,6 +96,9 @@ stubs_defaults { 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 @@ stubs_defaults { 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 @@ stubs_defaults { api_file: "api/current.txt", removed_api_file: "api/removed.txt", }, + api_lint: { + enabled: true, + }, }, dist: { targets: ["sdk", "win_sdk"], diff --git a/apex/extservices/Android.bp b/apex/extservices/Android.bp index 68350afdac85..0c6c4c23dce1 100644 --- a/apex/extservices/Android.bp +++ b/apex/extservices/Android.bp @@ -21,7 +21,7 @@ apex { 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/com/android/server/usage/AppStandbyInternal.java b/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java index 6d9e3eddf616..887d82c6413f 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 @@ public interface AppStandbyInternal { 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 @@ public interface AppStandbyInternal { 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/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java index 24728dd8edca..cb5cb175ff24 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 @@ public class AppStandbyController implements AppStandbyInternal { 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 @@ public class AppStandbyController implements AppStandbyInternal { 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; @@ -390,7 +390,16 @@ public class AppStandbyController implements AppStandbyInternal { @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 +572,23 @@ public class AppStandbyController implements AppStandbyInternal { 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)); } @@ -1502,6 +1523,15 @@ public class AppStandbyController implements AppStandbyInternal { } } + private void informParoleStateChanged() { + final boolean paroled = isInParole(); + synchronized (mPackageAccessListeners) { + for (AppIdleStateChangeListener listener : mPackageAccessListeners) { + listener.onParoleStateChanged(paroled); + } + } + } + @Override public void flushToDisk(int userId) { synchronized (mAppIdleLock) { @@ -1920,6 +1950,11 @@ public class AppStandbyController implements AppStandbyInternal { 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()); diff --git a/apex/media/framework/Android.bp b/apex/media/framework/Android.bp index a1c886a26562..3bc4f7b0ab72 100644 --- a/apex/media/framework/Android.bp +++ b/apex/media/framework/Android.bp @@ -102,6 +102,15 @@ droidstubs { "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 { @@ -110,6 +119,15 @@ droidstubs { "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 { @@ -118,6 +136,15 @@ droidstubs { "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 { diff --git a/apex/permission/framework/Android.bp b/apex/permission/framework/Android.bp index 3119b7d29b36..68c27a8327cb 100644 --- a/apex/permission/framework/Android.bp +++ b/apex/permission/framework/Android.bp @@ -55,6 +55,15 @@ droidstubs { "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 { @@ -63,6 +72,15 @@ droidstubs { "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 { @@ -71,6 +89,15 @@ droidstubs { "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 { diff --git a/apex/permission/service/Android.bp b/apex/permission/service/Android.bp index 2d92d00b6309..61449763540b 100644 --- a/apex/permission/service/Android.bp +++ b/apex/permission/service/Android.bp @@ -41,6 +41,15 @@ droidstubs { name: "service-permission-stubs-srcs", srcs: [ ":service-permission-sources" ], defaults: ["service-module-stubs-srcs-defaults"], + 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" }, } diff --git a/apex/sdkextensions/framework/Android.bp b/apex/sdkextensions/framework/Android.bp index 6a787116c005..14e23ed9a8a1 100644 --- a/apex/sdkextensions/framework/Android.bp +++ b/apex/sdkextensions/framework/Android.bp @@ -57,6 +57,15 @@ droidstubs { "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 { @@ -65,6 +74,15 @@ droidstubs { "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 { @@ -73,6 +91,15 @@ droidstubs { "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 { diff --git a/apex/statsd/framework/Android.bp b/apex/statsd/framework/Android.bp index 7d0f2ee274cd..9f5d933bb48a 100644 --- a/apex/statsd/framework/Android.bp +++ b/apex/statsd/framework/Android.bp @@ -93,6 +93,15 @@ droidstubs { "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 { @@ -101,6 +110,15 @@ droidstubs { "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 @@ droidstubs { "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 { diff --git a/apex/statsd/framework/java/android/app/StatsManager.java b/apex/statsd/framework/java/android/app/StatsManager.java index 7fbfc4318949..d1b7d8dc2c7a 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.Binder; 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 @@ public final class StatsManager { 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 93e6c108a289..5cf5e0b1d182 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.FileDescriptor; 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 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { private final HashMap<Long, String> mDeletedFiles = new HashMap<>(); private final CompanionHandler mHandler; - // Flag that is set when PHASE_BOOT_COMPLETED is triggered in the StatsCompanion lifecycle. This - // and the flag mSentBootComplete below is used for synchronization to ensure that the boot - // complete signal is only ever sent once to statsd. Two signals are needed because - // #sayHiToStatsd can be called from both statsd and #onBootPhase - // PHASE_THIRD_PARTY_APPS_CAN_START. - @GuardedBy("sStatsdLock") - private boolean mBootCompleted = false; - // Flag that is set when IStatsd#bootCompleted is called. This flag ensures that boot complete - // signal is only ever sent once. - @GuardedBy("sStatsdLock") - private boolean mSentBootComplete = false; + // 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 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { // 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 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { * 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 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { 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 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { // 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 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { private class StatsdDeathRecipient implements IBinder.DeathRecipient { - private List<BroadcastReceiver> mReceiversToUnregister; - - StatsdDeathRecipient() { - mReceiversToUnregister = new ArrayList<>(); - } + private final IStatsd mStatsd; + private final List<BroadcastReceiver> mReceiversToUnregister; - public void addRegisteredBroadcastReceivers(List<BroadcastReceiver> receivers) { - synchronized (sStatsdLock) { - mReceiversToUnregister.addAll(receivers); - } + StatsdDeathRecipient(IStatsd statsd, List<BroadcastReceiver> receivers) { + mStatsd = statsd; + mReceiversToUnregister = 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 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { } } } - // 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 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { } 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 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { } 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 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { 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 90764b0bd426..97846f2397a5 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 class StatsManagerService extends IStatsManagerService.Stub { 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/test-current.txt b/api/test-current.txt index 1e69d424a8b0..46049bd949c5 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -431,6 +431,7 @@ package android.app { } 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 @@ package android.view { 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/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp index bd9f7a59fcbd..a65f5f792daa 100644 --- a/cmds/statsd/src/StatsService.cpp +++ b/cmds/statsd/src/StatsService.cpp @@ -343,9 +343,11 @@ status_t StatsService::handleShellCommand(int in, int out, int err, const char** 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 3017ec024151..504890f6cf52 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -3021,14 +3021,14 @@ message LauncherUIChanged { 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; @@ -3036,7 +3036,7 @@ message LauncherUIChanged { 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; @@ -3044,6 +3044,9 @@ message LauncherUIChanged { // 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; } /** @@ -3064,22 +3067,34 @@ message LauncherStaticLayout { 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., WORKSPACE, HOTSEAT, FOLDER_WORKSPACE, FOLDER_HOTSEAT + // 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]; + + // 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]; } /** @@ -4886,8 +4901,6 @@ message MobileBytesTransfer { optional int64 tx_bytes = 4; optional int64 tx_packets = 5; - - optional int32 rat_type = 6; } /** @@ -4910,8 +4923,6 @@ message MobileBytesTransferByFgBg { optional int64 tx_bytes = 5; optional int64 tx_packets = 6; - - optional int32 rat_type = 7; } /** @@ -5699,7 +5710,7 @@ message ProcessStatsStateProto { optional AggStats rss = 8; } -// Next Tag: 7 +// Next Tag: 8 message ProcessStatsProto { // Name of process. optional string process = 1; @@ -5726,6 +5737,25 @@ message ProcessStatsProto { // 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 { @@ -9096,6 +9126,9 @@ message VoiceCallSession { // 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; } /** diff --git a/cmds/statsd/src/external/StatsCallbackPuller.cpp b/cmds/statsd/src/external/StatsCallbackPuller.cpp index 3618bb0dd08b..78e6f094db7e 100644 --- a/cmds/statsd/src/external/StatsCallbackPuller.cpp +++ b/cmds/statsd/src/external/StatsCallbackPuller.cpp @@ -86,6 +86,7 @@ bool StatsCallbackPuller::PullInternal(vector<shared_ptr<LogEvent>>* data) { // 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 5192ddf301e1..829a60345ba7 100644 --- a/cmds/statsd/src/external/StatsPuller.cpp +++ b/cmds/statsd/src/external/StatsPuller.cpp @@ -82,6 +82,11 @@ bool StatsPuller::Pull(std::vector<std::shared_ptr<LogEvent>>* data) { 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 cfd5d14b0d3b..1a52eb928777 100644 --- a/cmds/statsd/src/external/StatsPullerManager.cpp +++ b/cmds/statsd/src/external/StatsPullerManager.cpp @@ -111,12 +111,14 @@ bool StatsPullerManager::PullLocked(int tagId, const ConfigKey& configKey, 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 @@ bool StatsPullerManager::PullLocked(int tagId, const vector<int32_t>& uids, 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 @@ void StatsPullerManager::OnAlarmFired(int64_t elapsedTimeNs) { 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 @@ void StatsPullerManager::RegisterPullAtomCallback(const int uid, const int32_t a 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 46f5dbda5521..c027fffd20a0 100644 --- a/cmds/statsd/src/guardrail/StatsdStats.cpp +++ b/cmds/statsd/src/guardrail/StatsdStats.cpp @@ -472,14 +472,19 @@ void StatsdStats::notePullFailed(int atomId) { 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 @@ void StatsdStats::resetInternalLocked() { 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 @@ void StatsdStats::resetInternalLocked() { 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 @@ void StatsdStats::dumpStats(int out) const { " (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 805281ccd2d2..3d0eeb840064 100644 --- a/cmds/statsd/src/guardrail/StatsdStats.h +++ b/cmds/statsd/src/guardrail/StatsdStats.h @@ -371,21 +371,30 @@ public: 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 notePullUidProviderNotFound(int atomId); + + /** + * Records that the pull of an atom has failed due not finding a puller registered by a + * trusted uid. */ - void noteStatsCompanionPullFailed(int atomId); + void notePullerNotFound(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 has failed due to the outgoing binder call failing. */ - void noteStatsCompanionPullBinderTransactionFailed(int atomId); + void notePullBinderCallFailed(int atomId); /** * A pull with no data occurred @@ -503,12 +512,13 @@ public: 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 c4bd0549465a..cc4c56537c4c 100644 --- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp +++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp @@ -326,13 +326,12 @@ void GaugeMetricProducer::pullAndMatchEventsLocked(const int64_t timestampNs) { 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 @@ void GaugeMetricProducer::onDataPulled(const std::vector<std::shared_ptr<LogEven 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 f34423a27aff..e5ec72e3d0f5 100644 --- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp +++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp @@ -584,11 +584,6 @@ void ValueMetricProducer::accumulateEvents(const std::vector<std::shared_ptr<Log 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/stats_log.proto b/cmds/statsd/src/stats_log.proto index 868247bc9d64..1121392f1db0 100644 --- a/cmds/statsd/src/stats_log.proto +++ b/cmds/statsd/src/stats_log.proto @@ -456,12 +456,15 @@ message StatsdStatsReport { 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 2acffee0f443..bafdfcba59b2 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_DATA_ERROR = 9; 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 @@ void writePullerStatsToStream(const std::pair<int, StatsdStats::PulledAtomStats> (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 @@ void writePullerStatsToStream(const std::pair<int, StatsdStats::PulledAtomStats> 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 cdde603f4c0b..948d58706971 100644 --- a/cmds/statsd/tests/guardrail/StatsdStats_test.cpp +++ b/cmds/statsd/tests/guardrail/StatsdStats_test.cpp @@ -302,7 +302,10 @@ TEST(StatsdStatsTest, TestPullAtomStats) { 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 @@ TEST(StatsdStatsTest, TestPullAtomStats) { 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/tools/localtools/src/com/android/statsd/shelltools/testdrive/TestDrive.java b/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/testdrive/TestDrive.java index a97f132a2d5f..6384fb12ca68 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 @@ public class TestDrive { 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 77b3c81dee85..ed0ea556dc9d 100644 --- a/core/java/android/accessibilityservice/AccessibilityService.java +++ b/core/java/android/accessibilityservice/AccessibilityService.java @@ -513,6 +513,13 @@ public abstract class AccessibilityService extends Service { */ 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/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index 4d21c8d1a343..d3212884200d 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -66,6 +66,7 @@ import com.android.internal.app.IAppOpsAsyncNotedCallback; 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 @@ public class AppOpsManager { 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 @@ public class AppOpsManager { 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; @@ -6922,6 +6946,73 @@ public class AppOpsManager { } /** + * 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 @@ -6935,6 +7026,7 @@ public class AppOpsManager { * @param callback Where to report changes. * * @see #startWatchingActive(int[], OnOpActiveChangedListener) + * @see #startWatchingStarted(int[], OnOpStartedListener) * @see #stopWatchingNoted(OnOpNotedListener) * @see #noteOp(String, int, String, String, String) * @@ -6974,7 +7066,7 @@ public class AppOpsManager { */ 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/DreamManager.java b/core/java/android/app/DreamManager.java index fe13b8f26d78..f23681373f53 100644 --- a/core/java/android/app/DreamManager.java +++ b/core/java/android/app/DreamManager.java @@ -58,7 +58,7 @@ public class DreamManager { @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 @@ public class DreamManager { 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 833bfed573b2..e84c5e574713 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -99,7 +99,6 @@ interface IActivityManager { 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 @@ interface IActivityManager { * @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/content/ContentResolver.java b/core/java/android/content/ContentResolver.java index 0a4627da223a..c409613589b0 100644 --- a/core/java/android/content/ContentResolver.java +++ b/core/java/android/content/ContentResolver.java @@ -1449,7 +1449,7 @@ public abstract class ContentResolver implements ContentInterface { * 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 @@ public abstract class ContentResolver implements ContentInterface { /** * 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 @@ public abstract class ContentResolver implements ContentInterface { * * @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 @@ public abstract class ContentResolver implements ContentInterface { * @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 @@ public abstract class ContentResolver implements ContentInterface { * @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 @@ public abstract class ContentResolver implements ContentInterface { * @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 @@ public abstract class ContentResolver implements ContentInterface { * @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 @@ public abstract class ContentResolver implements ContentInterface { * 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 @@ public abstract class ContentResolver implements ContentInterface { * 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/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java index bbcac56cf8af..4299e805264c 100644 --- a/core/java/android/content/pm/LauncherApps.java +++ b/core/java/android/content/pm/LauncherApps.java @@ -1870,7 +1870,7 @@ public class LauncherApps { * 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 @@ public class LauncherApps { * * <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 d06a69caf837..4d718ef6bebe 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -47,8 +47,11 @@ import android.content.Context; 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; @@ -6037,28 +6040,24 @@ public abstract class PackageManager { @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()); } /** diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 3b3521f834aa..312e98e77636 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -1517,6 +1517,10 @@ public class PackageParser { ? 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 { diff --git a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java index 2f416a2538ba..d2172d3741d1 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.PackageInfo; 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 @@ public class ApkLiteParseUtils { * * @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); + + 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) { - throw new PackageParser.PackageParserException( - PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST, - "Split name " + lite.splitName - + " defined more than once; most recent was " + file); + // 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 @@ public class ApkLiteParseUtils { } 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 @@ public class ApkLiteParseUtils { * @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 @@ public class ApkLiteParseUtils { * @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 @@ public class ApkLiteParseUtils { ? 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 @@ public class ApkLiteParseUtils { 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 @@ public class ApkLiteParseUtils { } 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 @@ public class ApkLiteParseUtils { } } - 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 @@ public class ApkLiteParseUtils { 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 @@ public class ApkLiteParseUtils { 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 d3d15c82dd1b..9372c957af34 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.Build.VERSION_CODES.O; 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 @@ public class ParsingPackageUtils { * 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, callback); + 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; + } + + @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 @@ public class ParsingPackageUtils { 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 @@ public class ParsingPackageUtils { * 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 @@ public class ParsingPackageUtils { * 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 @@ public class ParsingPackageUtils { 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 @@ public class ParsingPackageUtils { * 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); @@ -430,20 +453,21 @@ public class ParsingPackageUtils { 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); @@ -2624,31 +2648,53 @@ public class ParsingPackageUtils { /** * 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; @@ -2657,9 +2703,10 @@ public class ParsingPackageUtils { } } - 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) { @@ -2667,27 +2714,31 @@ public class ParsingPackageUtils { 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/ParseTypeImpl.java b/core/java/android/content/pm/parsing/result/ParseTypeImpl.java index 61152061ae10..91e571be3d89 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 @@ package android.content.pm.parsing.result; 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 @@ public class ParseTypeImpl implements ParseInput, ParseResult<Object> { 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) { diff --git a/core/java/android/permission/PermissionControllerManager.java b/core/java/android/permission/PermissionControllerManager.java index ed429dd835c3..06caa03e3cb4 100644 --- a/core/java/android/permission/PermissionControllerManager.java +++ b/core/java/android/permission/PermissionControllerManager.java @@ -56,10 +56,15 @@ import com.android.internal.annotations.GuardedBy; 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.Arrays; 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 @@ public final class PermissionControllerManager { } /** + * 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 82a7d788100d..c6ede32d0864 100644 --- a/core/java/android/permission/PermissionControllerService.java +++ b/core/java/android/permission/PermissionControllerService.java @@ -50,9 +50,11 @@ import com.android.internal.infra.AndroidFuture; 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 @@ public abstract class PermissionControllerService extends Service { "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/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java index 2e00c0c9d2a4..327bca268a7b 100644 --- a/core/java/android/provider/DocumentsProvider.java +++ b/core/java/android/provider/DocumentsProvider.java @@ -1274,8 +1274,6 @@ public abstract class DocumentsProvider extends ContentProvider { 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 fdf3afd00529..c0d0c21af1ab 100755 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -5199,8 +5199,9 @@ public final class Settings { /** * 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 @@ -14032,6 +14033,14 @@ public final class Settings { "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 188670d0df50..678f43daaa38 100644 --- a/core/java/android/service/autofill/AutofillService.java +++ b/core/java/android/service/autofill/AutofillService.java @@ -455,7 +455,7 @@ import android.view.autofill.AutofillValue; * 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/IInlineSuggestionUi.aidl b/core/java/android/service/autofill/IInlineSuggestionUi.aidl new file mode 100644 index 000000000000..7289853064f8 --- /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 172cfef9fee2..97eb790b9acc 100644 --- a/core/java/android/service/autofill/IInlineSuggestionUiCallback.aidl +++ b/core/java/android/service/autofill/IInlineSuggestionUiCallback.aidl @@ -18,17 +18,19 @@ package android.service.autofill; 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 000000000000..0c2c624952eb --- /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/InlineSuggestionRenderService.java b/core/java/android/service/autofill/InlineSuggestionRenderService.java index 6c22b1936d74..3ea443bab3f8 100644 --- a/core/java/android/service/autofill/InlineSuggestionRenderService.java +++ b/core/java/android/service/autofill/InlineSuggestionRenderService.java @@ -33,6 +33,7 @@ import android.os.Looper; 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.View; 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 @@ public abstract class InlineSuggestionRenderService extends Service { 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 @@ -169,8 +193,14 @@ public abstract class InlineSuggestionRenderService extends Service { 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); } @@ -181,12 +211,87 @@ public abstract class InlineSuggestionRenderService extends Service { 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/augmented/AugmentedAutofillService.java b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java index cca45f572489..c2234bad3803 100644 --- a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java +++ b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java @@ -163,14 +163,18 @@ public abstract class AugmentedAutofillService extends Service { } /** - * 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 abstract class AugmentedAutofillService extends Service { */ 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 0a29edc81f2f..09d1bb9d2b12 100644 --- a/core/java/android/service/dreams/DreamActivity.java +++ b/core/java/android/service/dreams/DreamActivity.java @@ -21,6 +21,8 @@ import android.app.Activity; 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 @@ public class DreamActivity extends Activity { 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 337027ef5bc9..d2dfb29ba25c 100644 --- a/core/java/android/service/dreams/DreamService.java +++ b/core/java/android/service/dreams/DreamService.java @@ -1052,7 +1052,6 @@ public class DreamService extends Service implements Window.Callback { 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 @@ public class DreamService extends Service implements Window.Callback { @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/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java index cd20b357e2f1..6c619bb172a6 100644 --- a/core/java/android/util/FeatureFlagUtils.java +++ b/core/java/android/util/FeatureFlagUtils.java @@ -62,7 +62,7 @@ public class FeatureFlagUtils { 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/view/ImeInsetsSourceConsumer.java b/core/java/android/view/ImeInsetsSourceConsumer.java index 38b6c03a02f9..8b5af29517cb 100644 --- a/core/java/android/view/ImeInsetsSourceConsumer.java +++ b/core/java/android/view/ImeInsetsSourceConsumer.java @@ -143,9 +143,6 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer { 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 a135b0ca148b..fcc4a6ec4d92 100644 --- a/core/java/android/view/InsetsController.java +++ b/core/java/android/view/InsetsController.java @@ -1117,7 +1117,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation * 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/SurfaceControlViewHost.java b/core/java/android/view/SurfaceControlViewHost.java index 7ec008c901bc..7086dc09c8a3 100644 --- a/core/java/android/view/SurfaceControlViewHost.java +++ b/core/java/android/view/SurfaceControlViewHost.java @@ -272,8 +272,8 @@ public class SurfaceControlViewHost { * 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/View.java b/core/java/android/view/View.java index facf8619111c..1226202dfdf9 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -981,6 +981,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ 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 @@ public class View implements Drawable.Callback, KeyEvent.Callback, GradientDrawable.sWrapNegativeAngleMeasurements = targetSdkVersion >= Build.VERSION_CODES.Q; + + sForceLayoutWhenInsetsChanged = targetSdkVersion < Build.VERSION_CODES.R; + sCompatibilityDone = true; } } diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index b74c8f641a76..a17af6c90617 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -1584,6 +1584,11 @@ public final class ViewRootImpl implements ViewParent, 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 @@ public final class ViewRootImpl implements ViewParent, 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 d8bf58f78339..9674a80c8159 100644 --- a/core/java/android/view/ViewRootInsetsControllerHost.java +++ b/core/java/android/view/ViewRootInsetsControllerHost.java @@ -104,10 +104,10 @@ public class ViewRootInsetsControllerHost implements InsetsController.Host { @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 b1536484b515..446e7aa67bc5 100644 --- a/core/java/android/view/Window.java +++ b/core/java/android/view/Window.java @@ -26,6 +26,7 @@ import android.annotation.NonNull; 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 class Window { 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/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java index 95d6d651cc79..15604a2ae2c1 100644 --- a/core/java/android/view/WindowlessWindowManager.java +++ b/core/java/android/view/WindowlessWindowManager.java @@ -41,6 +41,7 @@ public class WindowlessWindowManager implements IWindowSession { 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; @@ -239,21 +240,19 @@ public class WindowlessWindowManager implements IWindowSession { } 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); diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java index 6d3dbfe16b78..1773ec2b17ee 100644 --- a/core/java/android/view/autofill/AutofillManager.java +++ b/core/java/android/view/autofill/AutofillManager.java @@ -883,6 +883,25 @@ public final class AutofillManager { } /** + * 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 @@ public final class AutofillManager { * 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; } @@ -3484,7 +3503,7 @@ public final class AutofillManager { 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 6b1a480986c8..4c72474435a4 100644 --- a/core/java/android/view/inputmethod/InlineSuggestion.java +++ b/core/java/android/view/inputmethod/InlineSuggestion.java @@ -18,11 +18,13 @@ package android.view.inputmethod; 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.concurrent.Executor; 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 @@ public final class InlineSuggestion implements Parcelable { * @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 @@ public final class InlineSuggestion implements Parcelable { * * @hide */ - public InlineSuggestion( - @NonNull InlineSuggestionInfo info, + public InlineSuggestion(@NonNull InlineSuggestionInfo info, @Nullable IInlineContentProvider contentProvider) { this(info, contentProvider, /* inlineContentCallback */ null); } @@ -96,25 +98,30 @@ public final class InlineSuggestion implements Parcelable { /** * 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 @@ public final class InlineSuggestion implements Parcelable { + ", 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 @@ public final class InlineSuggestion implements Parcelable { 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 @@ public final class InlineSuggestion implements Parcelable { } } + /** + * 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 @@ public final class InlineSuggestion implements Parcelable { @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 @@ public final class InlineSuggestion implements Parcelable { + // Code below generated by codegen v1.0.15. // // DO NOT MODIFY! @@ -302,6 +446,14 @@ public final class InlineSuggestion implements Parcelable { } /** + * @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 @@ public final class InlineSuggestion implements Parcelable { }; @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/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index 3cf61098f11c..71dd6653f6a6 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -645,6 +645,11 @@ public final class InputMethodManager { @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/widget/inline/InlineContentView.java b/core/java/android/widget/inline/InlineContentView.java index 4f2af63626cf..8657e828a3f6 100644 --- a/core/java/android/widget/inline/InlineContentView.java +++ b/core/java/android/widget/inline/InlineContentView.java @@ -21,40 +21,45 @@ import android.annotation.Nullable; 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 @@ public class InlineContentView extends ViewGroup { 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 @@ public class InlineContentView extends ViewGroup { } }; - private final @NonNull SurfaceView mSurfaceView; + @NonNull + private final SurfaceView mSurfaceView; + + @Nullable + private SurfaceControlCallback mSurfaceControlCallback; - private @Nullable SurfaceControlCallback mSurfaceControlCallback; + @Nullable + private SurfacePackageUpdater mSurfacePackageUpdater; /** * @inheritDoc - * * @hide */ public InlineContentView(@NonNull Context context) { @@ -105,7 +140,6 @@ public class InlineContentView extends ViewGroup { /** * @inheritDoc - * * @hide */ public InlineContentView(@NonNull Context context, @Nullable AttributeSet attrs) { @@ -114,7 +148,6 @@ public class InlineContentView extends ViewGroup { /** * @inheritDoc - * * @hide */ public InlineContentView(@NonNull Context context, @Nullable AttributeSet attrs, @@ -123,20 +156,18 @@ public class InlineContentView extends ViewGroup { } /** - * 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 @@ public class InlineContentView extends ViewGroup { } /** - * 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 @@ public class InlineContentView extends ViewGroup { } /** - * 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 @@ public class InlineContentView extends ViewGroup { /** * @return Whether the surface backing this view appears on top of its parent. - * * @see #setZOrderedOnTop(boolean) */ public boolean isZOrderedOnTop() { @@ -190,17 +241,15 @@ public class InlineContentView extends ViewGroup { } /** - * 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/window/TaskEmbedder.java b/core/java/android/window/TaskEmbedder.java index 4257ce084829..ca6c568c2668 100644 --- a/core/java/android/window/TaskEmbedder.java +++ b/core/java/android/window/TaskEmbedder.java @@ -36,11 +36,14 @@ 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.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; @@ -184,31 +187,45 @@ public abstract class TaskEmbedder { /** * 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. @@ -268,6 +285,48 @@ public abstract class TaskEmbedder { } /** + * 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 2fb46509f337..1b87521f3a96 100644 --- a/core/java/android/window/TaskOrganizerTaskEmbedder.java +++ b/core/java/android/window/TaskOrganizerTaskEmbedder.java @@ -75,7 +75,8 @@ public class TaskOrganizerTaskEmbedder extends TaskEmbedder { // infrastructure is ready. mTaskOrganizer.registerOrganizer(WINDOWING_MODE_MULTI_WINDOW); mTaskOrganizer.setInterceptBackPressedOnTaskRoot(true); - return true; + + return super.onInitialize(); } @Override @@ -96,6 +97,7 @@ public class TaskOrganizerTaskEmbedder extends TaskEmbedder { */ @Override public void start() { + super.start(); if (DEBUG) { log("start"); } @@ -119,6 +121,7 @@ public class TaskOrganizerTaskEmbedder extends TaskEmbedder { */ @Override public void stop() { + super.stop(); if (DEBUG) { log("stop"); } @@ -143,6 +146,7 @@ public class TaskOrganizerTaskEmbedder extends TaskEmbedder { */ @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 6f85dc263a4d..2e6cbeee7d22 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_OWN_C 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.RemoteException; 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 @@ public class VirtualDisplayTaskEmbedder extends TaskEmbedder { 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 @@ public class VirtualDisplayTaskEmbedder extends TaskEmbedder { */ @Override public void start() { + super.start(); if (isInitialized()) { mVirtualDisplay.setDisplayState(true); - updateLocationAndTapExcludeRegion(); } } @@ -181,23 +174,14 @@ public class VirtualDisplayTaskEmbedder extends TaskEmbedder { */ @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 @@ -298,12 +282,13 @@ public class VirtualDisplayTaskEmbedder extends TaskEmbedder { * 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()); } /** @@ -332,24 +317,6 @@ public class VirtualDisplayTaskEmbedder extends TaskEmbedder { } /** - * 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() { @@ -357,17 +324,6 @@ public class VirtualDisplayTaskEmbedder extends TaskEmbedder { 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 e0bbc04515e0..28c9464fbf66 100644 --- a/core/java/com/android/internal/app/AbstractResolverComparator.java +++ b/core/java/com/android/internal/app/AbstractResolverComparator.java @@ -43,7 +43,7 @@ import java.util.List; 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 986614c0963c..37a5a63265e8 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.Intent; import android.content.pm.ResolveInfo; import android.os.Message; import android.os.UserHandle; +import android.provider.DeviceConfig; import android.util.Log; import com.android.internal.app.ResolverActivity.ResolvedComponentInfo; +import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; import java.util.ArrayList; import java.util.HashMap; @@ -48,7 +50,6 @@ import java.util.stream.Collectors; 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 @@ class AppPredictionServiceResolverComparator extends AbstractResolverComparator // back to using the ResolverRankerService. private ResolverRankerServiceResolverComparator mResolverRankerService; + private boolean mAppendDirectShareEnabled = DeviceConfig.getBoolean( + DeviceConfig.NAMESPACE_SYSTEMUI, + SystemUiDeviceConfigFlags.APPEND_DIRECT_SHARE_ENABLED, + true); + AppPredictionServiceResolverComparator( Context context, Intent intent, @@ -113,9 +119,7 @@ class AppPredictionServiceResolverComparator extends AbstractResolverComparator 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 @@ class AppPredictionServiceResolverComparator extends AbstractResolverComparator () -> 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 @@ class AppPredictionServiceResolverComparator extends AbstractResolverComparator 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 @@ class AppPredictionServiceResolverComparator extends AbstractResolverComparator 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 a144ffb57a15..3fc3f3e65d37 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.AppPredictionManager; 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 @@ public class ChooserActivity extends ResolverActivity implements private static final String TAG = "ChooserActivity"; private AppPredictor mPersonalAppPredictor; private AppPredictor mWorkAppPredictor; + private boolean mShouldDisplayLandscape; @UnsupportedAppUsage public ChooserActivity() { @@ -191,6 +193,8 @@ public class ChooserActivity extends ResolverActivity implements // 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 @@ public class ChooserActivity extends ResolverActivity implements 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 @@ public class ChooserActivity extends ResolverActivity implements private static final int SHORTCUT_MANAGER_SHARE_TARGET_RESULT = 4; private static final int SHORTCUT_MANAGER_SHARE_TARGET_RESULT_COMPLETED = 5; private static final int LIST_VIEW_UPDATE_MESSAGE = 6; + private static final int CHOOSER_TARGET_RANKING_SCORE = 7; private static final int WATCHDOG_TIMEOUT_MAX_MILLIS = 10000; private static final int WATCHDOG_TIMEOUT_MIN_MILLIS = 3000; @@ -448,6 +457,7 @@ public class ChooserActivity extends ResolverActivity implements removeMessages(CHOOSER_TARGET_SERVICE_RESULT); removeMessages(SHORTCUT_MANAGER_SHARE_TARGET_RESULT); removeMessages(SHORTCUT_MANAGER_SHARE_TARGET_RESULT_COMPLETED); + removeMessages(CHOOSER_TARGET_RANKING_SCORE); } private void restartServiceRequestTimer() { @@ -559,6 +569,17 @@ public class ChooserActivity extends ResolverActivity implements getChooserActivityLogger().logSharesheetDirectLoadComplete(); break; + case CHOOSER_TARGET_RANKING_SCORE: + if (DEBUG) Log.d(TAG, "CHOOSER_TARGET_RANKING_SCORE"); + final ChooserTargetRankingInfo scoreInfo = (ChooserTargetRankingInfo) msg.obj; + ChooserListAdapter adapterForUserHandle = + mChooserMultiProfilePagerAdapter.getListAdapterForUserHandle( + scoreInfo.userHandle); + if (adapterForUserHandle != null) { + adapterForUserHandle.addChooserTargetRankingScore(scoreInfo.scores); + } + break; + default: super.handleMessage(msg); } @@ -696,6 +717,8 @@ public class ChooserActivity extends ResolverActivity implements 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 @@ public class ChooserActivity extends ResolverActivity implements 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 @@ public class ChooserActivity extends ResolverActivity implements /* context */ this, adapter, getPersonalProfileUserHandle(), - /* workProfileUserHandle= */ null); + /* workProfileUserHandle= */ null, + isSendAction(getTargetIntent())); } private ChooserMultiProfilePagerAdapter createChooserMultiProfilePagerAdapterForTwoProfiles( @@ -878,7 +918,8 @@ public class ChooserActivity extends ResolverActivity implements workAdapter, selectedProfile, getPersonalProfileUserHandle(), - getWorkProfileUserHandle()); + getWorkProfileUserHandle(), + isSendAction(getTargetIntent())); } private int findSelectedProfile() { @@ -1035,6 +1076,7 @@ public class ChooserActivity extends ResolverActivity implements public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); + mShouldDisplayLandscape = shouldDisplayLandscape(newConfig.orientation); adjustPreviewWidth(newConfig.orientation, null); updateStickyContentPreview(); } @@ -1048,7 +1090,7 @@ public class ChooserActivity extends ResolverActivity implements 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 @@ public class ChooserActivity extends ResolverActivity implements }); } + 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 @@ public class ChooserActivity extends ResolverActivity implements 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 @@ public class ChooserActivity extends ResolverActivity implements 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 @@ public class ChooserActivity extends ResolverActivity implements if (mDirectShareAppTargetCache != null) { appTarget = mDirectShareAppTargetCache.get(chooserTarget); } + if (mChooserTargetRankingEnabled && appTarget == null) { + // Send ChooserTarget sharing info to AppPredictor. + ComponentName componentName = 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 @@ public class ChooserActivity extends ResolverActivity implements .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 @@ public class ChooserActivity extends ResolverActivity implements * {@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 @@ public class ChooserActivity extends ResolverActivity implements /** * 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 @@ public class ChooserActivity extends ResolverActivity implements 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 class ChooserActivity extends ResolverActivity implements 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 @@ public class ChooserActivity extends ResolverActivity implements 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 @@ public class ChooserActivity extends ResolverActivity implements @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 @@ public class ChooserActivity extends ResolverActivity implements } viewGroup.setTag(holder); - return holder; } @@ -3252,14 +3369,15 @@ public class ChooserActivity extends ResolverActivity implements 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 @@ public class ChooserActivity extends ResolverActivity implements * {@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 @@ public class ChooserActivity extends ResolverActivity implements 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 @@ public class ChooserActivity extends ResolverActivity implements 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 @@ public class ChooserActivity extends ResolverActivity implements } } + 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 000000000000..317a987cf359 --- /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 73ee2950c481..f426bc0ecbb5 100644 --- a/core/java/com/android/internal/app/ChooserListAdapter.java +++ b/core/java/com/android/internal/app/ChooserListAdapter.java @@ -21,6 +21,7 @@ import static com.android.internal.app.ChooserActivity.TARGET_TYPE_SHORTCUTS_FRO import android.app.ActivityManager; import android.app.prediction.AppPredictor; +import android.app.prediction.AppTarget; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -98,6 +99,7 @@ public class ChooserListAdapter extends ResolverListAdapter { 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 @@ public class ChooserListAdapter extends ResolverListAdapter { 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 @@ public class ChooserListAdapter extends ResolverListAdapter { } /** + * Store ChooserTarget ranking scores info wrapped in {@code targets}. + */ + public void addChooserTargetRankingScore(List<AppTarget> targets) { + Log.i(TAG, "addChooserTargetRankingScore " + targets.size() + " targets score."); + for (AppTarget target : targets) { + if (target.getShortcutInfo() == null) { + continue; + } + ShortcutInfo shortcutInfo = target.getShortcutInfo(); + if (!shortcutInfo.getId().equals(ChooserActivity.CHOOSER_TARGET) + || shortcutInfo.getActivity() == null) { + continue; + } + ComponentName componentName = shortcutInfo.getActivity(); + if (!mChooserTargetScores.containsKey(componentName)) { + mChooserTargetScores.put(componentName, new HashMap<>()); + } + mChooserTargetScores.get(componentName).put(shortcutInfo.getShortLabel().toString(), + 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 @@ public class ChooserListAdapter extends ResolverListAdapter { 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 57157f7b1f5b..774be3c9c4b8 100644 --- a/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java +++ b/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java @@ -37,15 +37,18 @@ public class ChooserMultiProfilePagerAdapter extends AbstractMultiProfilePagerAd 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 @@ public class ChooserMultiProfilePagerAdapter extends AbstractMultiProfilePagerAd 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 @@ public class ChooserMultiProfilePagerAdapter extends AbstractMultiProfilePagerAd @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 000000000000..3f8788cba9b9 --- /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 921882348328..06c21ab8832d 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.IAppOpsCallback; 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 @@ interface IAppOpsService { 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 000000000000..ed521e656981 --- /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 2c4892561ddd..fca156a97a83 100644 --- a/core/java/com/android/internal/app/IntentForwarderActivity.java +++ b/core/java/com/android/internal/app/IntentForwarderActivity.java @@ -80,6 +80,12 @@ public class IntentForwarderActivity extends Activity { 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 @@ public class IntentForwarderActivity extends Activity { 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 @@ public class IntentForwarderActivity extends Activity { 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 2f62f8e7a0c9..83dabe8d0525 100644 --- a/core/java/com/android/internal/app/ResolverActivity.java +++ b/core/java/com/android/internal/app/ResolverActivity.java @@ -182,6 +182,8 @@ public class ResolverActivity extends Activity implements 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 @@ public class ResolverActivity extends Activity implements // 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 @@ public class ResolverActivity extends Activity implements 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 2fd938f45291..24bf98b6502c 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.R; 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 @@ public class ResolverListAdapter extends BaseAdapter { 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 @@ public class ResolverListAdapter extends BaseAdapter { 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 246a07d3d0fe..900e18d468bb 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.ResolverListAdapter.ActivityInfoPresentationGett import com.android.internal.app.SimpleIconFactory; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; /** @@ -136,6 +135,10 @@ public final class SelectableTargetInfo implements ChooserTargetInfo { 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 dea35669b591..8fef8378f33c 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 @@ public final class AssociationState { /** * 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 7a6301f6f180..a2eca3aee13d 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 @@ interface IProcessStats { */ 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 fe4138584fa7..b8142607ebd7 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.os.UserHandle; 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.TimeUtils; 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 @@ public final class ProcessState { /** 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 @@ public final class ProcessState { 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 80f6272794d1..928ba35595d3 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.content.ComponentName; 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.TimeUtils; 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 final class ProcessStats implements Parcelable { 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 @@ public final class ProcessStats implements Parcelable { final ProcessState procState = uids.valueAt(iu); procState.dumpAggregatedProtoForStatsd(proto, ProcessStatsSectionProto.PROCESS_STATS, - procName, uid, mTimePeriodEndRealtime); + procName, uid, mTimePeriodEndRealtime, procToPkgMap); } } } @@ -2268,6 +2276,135 @@ public final class ProcessStats implements Parcelable { } } + /** + * 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 2b0fd663643d..6f33096a14fd 100644 --- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java +++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java @@ -389,6 +389,11 @@ public final class SystemUiDeviceConfigFlags { 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"; diff --git a/core/java/com/android/internal/infra/AbstractRemoteService.java b/core/java/com/android/internal/infra/AbstractRemoteService.java index 3900f1674c13..7195b45a4055 100644 --- a/core/java/com/android/internal/infra/AbstractRemoteService.java +++ b/core/java/com/android/internal/infra/AbstractRemoteService.java @@ -321,6 +321,20 @@ public abstract class AbstractRemoteService<S extends AbstractRemoteService<S, I 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 863659d7c4eb..c6135f2c81d3 100644 --- a/core/java/com/android/internal/policy/DecorView.java +++ b/core/java/com/android/internal/policy/DecorView.java @@ -324,6 +324,14 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind 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/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java index aa75d4010748..c5729b05c587 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_ADJUST_RESIZE; 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 class PhoneWindow extends Window implements MenuBuilder.Callback { 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 1fce098fb93e..1ec020696cf3 100644 --- a/core/java/com/android/internal/policy/TaskResizingAlgorithm.java +++ b/core/java/com/android/internal/policy/TaskResizingAlgorithm.java @@ -91,14 +91,14 @@ public class TaskResizingAlgorithm { 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/util/FunctionalUtils.java b/core/java/com/android/internal/util/FunctionalUtils.java index 9168438dc2bf..05ecdf905623 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.os.RemoteException; 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 @@ public class FunctionalUtils { } /** + * 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 08a349c21c8b..78df3eb660a5 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 @@ import com.android.internal.view.inline.IInlineContentCallback; */ 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 e0502f129f7f..09e6a991b1ac 100644 --- a/core/java/com/android/internal/widget/GridLayoutManager.java +++ b/core/java/com/android/internal/widget/GridLayoutManager.java @@ -153,13 +153,11 @@ public class GridLayoutManager extends LinearLayoutManager { 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/ResolverDrawerLayout.java b/core/java/com/android/internal/widget/ResolverDrawerLayout.java index fb2ecf3a478f..3f708f84750c 100644 --- a/core/java/com/android/internal/widget/ResolverDrawerLayout.java +++ b/core/java/com/android/internal/widget/ResolverDrawerLayout.java @@ -825,18 +825,6 @@ public class ResolverDrawerLayout extends ViewGroup { 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 @@ public class ResolverDrawerLayout extends ViewGroup { } 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/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto index d5384a1c2fdd..762895b6320f 100644 --- a/core/proto/android/providers/settings/global.proto +++ b/core/proto/android/providers/settings/global.proto @@ -169,6 +169,7 @@ message GlobalSettingsProto { 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 @@ message GlobalSettingsProto { // 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 a6dc937566c2..dd830a85edc9 100644 --- a/core/proto/android/service/procstats.proto +++ b/core/proto/android/service/procstats.proto @@ -142,7 +142,7 @@ message ProcessStatsStateProto { 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 @@ message ProcessStatsProto { // 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 a23277eddf2b..0bf504595714 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 000000000000..c4599dad31a0 --- /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 000000000000..9e1c6e2ee0d7 --- /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 000000000000..740f52856b7f --- /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 696912b257ac..955663fa48e9 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 6b1b002267cb..86dc71cbbfb8 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 4d0837f495df..446ce3fbaf4b 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 face71441244..a1a84ae16ebf 100644 --- a/core/res/res/values-af/strings.xml +++ b/core/res/res/values-af/strings.xml @@ -2042,8 +2042,12 @@ <string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Kragdialoog"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Sluitskerm"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Skermkiekie"</string> - <string name="accessibility_system_action_accessibility_button_label" msgid="5941347017132886642">"Toeganklikheidkortpad op skerm"</string> - <string name="accessibility_system_action_accessibility_button_chooser_label" msgid="6973618519666227981">"Toeganklikheidkortpadkieser op skerm"</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> 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> diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml index 634da0bb0964..a32e6919f0be 100644 --- a/core/res/res/values-am/strings.xml +++ b/core/res/res/values-am/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-ar/strings.xml b/core/res/res/values-ar/strings.xml index f9444af77070..4faac2ad1de4 100644 --- a/core/res/res/values-ar/strings.xml +++ b/core/res/res/values-ar/strings.xml @@ -1886,8 +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> - <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="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> @@ -2178,12 +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> - <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> - <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"أُرسِلت صورة"</string> + <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 346850a47392..b56470759107 100644 --- a/core/res/res/values-as/strings.xml +++ b/core/res/res/values-as/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>ক সীমাবদ্ধ বাকেটটোত ৰখা হৈছে"</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-az/strings.xml b/core/res/res/values-az/strings.xml index 2b302b54ae51..0f0c717a3cf8 100644 --- a/core/res/res/values-az/strings.xml +++ b/core/res/res/values-az/strings.xml @@ -2042,8 +2042,12 @@ <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> - <string name="accessibility_system_action_accessibility_button_label" msgid="5941347017132886642">"Ekranda Əlçatımlılıq Qısayolu"</string> - <string name="accessibility_system_action_accessibility_button_chooser_label" msgid="6973618519666227981">"Ekranda Əlçatımlılıq Qısayolu Seçicisi"</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> 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> diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml index a7f5b764e432..61342ac63767 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,8 +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> - <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="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> @@ -1885,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> @@ -1920,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> @@ -1930,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> @@ -2076,8 +2076,12 @@ <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> - <string name="accessibility_system_action_accessibility_button_label" msgid="5941347017132886642">"Prečice za pristupačnost na ekranu"</string> - <string name="accessibility_system_action_accessibility_button_chooser_label" msgid="6973618519666227981">"Alatka za biranje prečica za pristupačnost na ekranu"</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">"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> @@ -2090,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 994c548aab6e..0fc6572ec98f 100644 --- a/core/res/res/values-be/strings.xml +++ b/core/res/res/values-be/strings.xml @@ -2110,8 +2110,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-bg/strings.xml b/core/res/res/values-bg/strings.xml index 7ddebd0b3d26..579c80d5c206 100644 --- a/core/res/res/values-bg/strings.xml +++ b/core/res/res/values-bg/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> е поставен в ОГРАНИЧЕНИЯ контейнер"</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-bn/strings.xml b/core/res/res/values-bn/strings.xml index 7052bc0bfb73..0505a3ecd840 100644 --- a/core/res/res/values-bn/strings.xml +++ b/core/res/res/values-bn/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> সীমাবদ্ধ গ্রুপে অন্তর্ভুক্ত করা হয়েছে"</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-bs/strings.xml b/core/res/res/values-bs/strings.xml index 45bb18d1324d..23b3cc0f95c6 100644 --- a/core/res/res/values-bs/strings.xml +++ b/core/res/res/values-bs/strings.xml @@ -2078,8 +2078,12 @@ <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> - <string name="accessibility_system_action_accessibility_button_label" msgid="5941347017132886642">"Prečica za pristupačnost na ekranu"</string> - <string name="accessibility_system_action_accessibility_button_chooser_label" msgid="6973618519666227981">"Okvir za odabir prečice za pristupačnost na ekranu"</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">"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> diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml index 33c2595eca02..23863a50526c 100644 --- a/core/res/res/values-ca/strings.xml +++ b/core/res/res/values-ca/strings.xml @@ -1797,7 +1797,7 @@ <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> @@ -2042,8 +2042,12 @@ <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> - <string name="accessibility_system_action_accessibility_button_label" msgid="5941347017132886642">"Drecera d\'accessibilitat en pantalla"</string> - <string name="accessibility_system_action_accessibility_button_chooser_label" msgid="6973618519666227981">"Selector de dreceres d\'accessibilitat en pantalla"</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">"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> diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml index 53216782756d..03f36913ddbb 100644 --- a/core/res/res/values-cs/strings.xml +++ b/core/res/res/values-cs/strings.xml @@ -1840,8 +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> - <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="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> @@ -2110,12 +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> - <string name="accessibility_system_action_accessibility_button_label" msgid="5941347017132886642">"Zkratka přístupnosti na obrazovce"</string> - <string name="accessibility_system_action_accessibility_button_chooser_label" msgid="6973618519666227981">"Výběr zkratky přístupnosti na obrazovce"</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">"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> - <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"odesílá obrázek"</string> + <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 0c308e28a1b1..916565f9312a 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -2042,8 +2042,12 @@ <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> - <string name="accessibility_system_action_accessibility_button_label" msgid="5941347017132886642">"Genvej til hjælpefunktioner på skærmen"</string> - <string name="accessibility_system_action_accessibility_button_chooser_label" msgid="6973618519666227981">"Valg af genvej til hjælpefunktioner på skærmen"</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">"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> diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml index 62658c0fae24..e5c269ec8fa4 100644 --- a/core/res/res/values-de/strings.xml +++ b/core/res/res/values-de/strings.xml @@ -2042,8 +2042,12 @@ <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> - <string name="accessibility_system_action_accessibility_button_label" msgid="5941347017132886642">"Verknüpfung für Bildschirmbedienungshilfe"</string> - <string name="accessibility_system_action_accessibility_button_chooser_label" msgid="6973618519666227981">"Auswahl für Verknüpfungen für Bildschirmbedienungshilfen"</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">"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> diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml index cf6c4138b306..6a2ceb3cb8d5 100644 --- a/core/res/res/values-el/strings.xml +++ b/core/res/res/values-el/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> τοποθετήθηκε στον κάδο ΠΕΡΙΟΡΙΣΜΕΝΗΣ ΠΡΟΣΒΑΣΗΣ."</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-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml index a6cec0d58ecf..9020dae6b280 100644 --- a/core/res/res/values-en-rAU/strings.xml +++ b/core/res/res/values-en-rAU/strings.xml @@ -2042,8 +2042,12 @@ <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> - <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> + <!-- 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">"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-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml index 188d9a787bd9..51397c720f2e 100644 --- a/core/res/res/values-en-rCA/strings.xml +++ b/core/res/res/values-en-rCA/strings.xml @@ -2042,8 +2042,12 @@ <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> - <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> + <!-- 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">"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-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml index a6cec0d58ecf..9020dae6b280 100644 --- a/core/res/res/values-en-rGB/strings.xml +++ b/core/res/res/values-en-rGB/strings.xml @@ -2042,8 +2042,12 @@ <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> - <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> + <!-- 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">"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-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml index a6cec0d58ecf..9020dae6b280 100644 --- a/core/res/res/values-en-rIN/strings.xml +++ b/core/res/res/values-en-rIN/strings.xml @@ -2042,8 +2042,12 @@ <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> - <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> + <!-- 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">"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-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml index ed957de9303d..9787079c5e23 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 2daab157b0b7..a7a053405742 100644 --- a/core/res/res/values-es-rUS/strings.xml +++ b/core/res/res/values-es-rUS/strings.xml @@ -2042,8 +2042,12 @@ <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> - <string name="accessibility_system_action_accessibility_button_label" msgid="5941347017132886642">"Acceso directo de accesibilidad en pantalla"</string> - <string name="accessibility_system_action_accessibility_button_chooser_label" msgid="6973618519666227981">"Selector del acceso directo de accesibilidad en pantalla"</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">"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> diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index 7d93cd87c8b8..a3a9f78b383b 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -2042,8 +2042,12 @@ <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> - <string name="accessibility_system_action_accessibility_button_label" msgid="5941347017132886642">"Acceso directo de accesibilidad en pantalla"</string> - <string name="accessibility_system_action_accessibility_button_chooser_label" msgid="6973618519666227981">"Opción de acceso directo de accesibilidad en pantalla"</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">"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> diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml index fce1700bea15..ddb89afaa7c9 100644 --- a/core/res/res/values-et/strings.xml +++ b/core/res/res/values-et/strings.xml @@ -2042,8 +2042,12 @@ <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> - <string name="accessibility_system_action_accessibility_button_label" msgid="5941347017132886642">"Ekraanil kuvatav juurdepääsetavuse otsetee"</string> - <string name="accessibility_system_action_accessibility_button_chooser_label" msgid="6973618519666227981">"Ekraanil kuvatav juurdepääsetavuse otsetee valija"</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">"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> diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml index eaf579eef469..26bbaa57b193 100644 --- a/core/res/res/values-eu/strings.xml +++ b/core/res/res/values-eu/strings.xml @@ -1794,8 +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> - <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="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> @@ -2042,8 +2042,12 @@ <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> - <string name="accessibility_system_action_accessibility_button_label" msgid="5941347017132886642">"Pantailako erabilerraztasun-lasterbidea"</string> - <string name="accessibility_system_action_accessibility_button_chooser_label" msgid="6973618519666227981">"Pantailako erabilerraztasun-lasterbideen hautatzailea"</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> 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> diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml index 0aaa58ee74cf..f77d015b0892 100644 --- a/core/res/res/values-fa/strings.xml +++ b/core/res/res/values-fa/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> در سطل «محدودشده» قرار گرفت"</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-fi/strings.xml b/core/res/res/values-fi/strings.xml index 4d5b6c335f67..9f50d775c693 100644 --- a/core/res/res/values-fi/strings.xml +++ b/core/res/res/values-fi/strings.xml @@ -2042,8 +2042,12 @@ <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> - <string name="accessibility_system_action_accessibility_button_label" msgid="5941347017132886642">"Näytöllä näkyvä esteettömyyspainike"</string> - <string name="accessibility_system_action_accessibility_button_chooser_label" msgid="6973618519666227981">"Näytöllä näkyvän esteettömyyspainikkeen valitsin"</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">"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> diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml index a82b40184140..2a9de6638c11 100644 --- a/core/res/res/values-fr-rCA/strings.xml +++ b/core/res/res/values-fr-rCA/strings.xml @@ -2042,8 +2042,12 @@ <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> - <string name="accessibility_system_action_accessibility_button_label" msgid="5941347017132886642">"Raccourci d\'accessibilité à l\'écran"</string> - <string name="accessibility_system_action_accessibility_button_chooser_label" msgid="6973618519666227981">"Sélecteur de raccourci d\'accessibilité à l\'écran"</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">"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> diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index 72bcd8d645bf..224dcfeb9855 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -2042,8 +2042,12 @@ <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> - <string name="accessibility_system_action_accessibility_button_label" msgid="5941347017132886642">"Raccourci d\'accessibilité à l\'écran"</string> - <string name="accessibility_system_action_accessibility_button_chooser_label" msgid="6973618519666227981">"Outil de sélection des raccourcis d\'accessibilité à l\'écran"</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">"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> diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml index e10afae8b27d..cfd555a21c9a 100644 --- a/core/res/res/values-gl/strings.xml +++ b/core/res/res/values-gl/strings.xml @@ -2042,8 +2042,12 @@ <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> - <string name="accessibility_system_action_accessibility_button_label" msgid="5941347017132886642">"Atallo de accesibilidade en pantalla"</string> - <string name="accessibility_system_action_accessibility_button_chooser_label" msgid="6973618519666227981">"Selector de atallos de accesibilidade en pantalla"</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">"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> diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml index 6e3a4eb91c8b..cf7afb5e9e9c 100644 --- a/core/res/res/values-gu/strings.xml +++ b/core/res/res/values-gu/strings.xml @@ -1888,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> @@ -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-hi/strings.xml b/core/res/res/values-hi/strings.xml index 4cd6a5b112fe..5038d72734ab 100644 --- a/core/res/res/values-hi/strings.xml +++ b/core/res/res/values-hi/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> को प्रतिबंधित बकेट में रखा गया है"</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-hr/strings.xml b/core/res/res/values-hr/strings.xml index 6d0531ec5b0b..a4586136eac5 100644 --- a/core/res/res/values-hr/strings.xml +++ b/core/res/res/values-hr/strings.xml @@ -2076,8 +2076,12 @@ <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> - <string name="accessibility_system_action_accessibility_button_label" msgid="5941347017132886642">"Prečac pristupačnosti na zaslonu"</string> - <string name="accessibility_system_action_accessibility_button_chooser_label" msgid="6973618519666227981">"Alat za odabir prečaca pristupačnosti na zaslonu"</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">"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> diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml index e14c848cf6f7..f2e024d5e7ad 100644 --- a/core/res/res/values-hu/strings.xml +++ b/core/res/res/values-hu/strings.xml @@ -2042,8 +2042,12 @@ <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> - <string name="accessibility_system_action_accessibility_button_label" msgid="5941347017132886642">"Képernyőn megjelenő kisegítő lehetőségekre vonatkozó parancs"</string> - <string name="accessibility_system_action_accessibility_button_chooser_label" msgid="6973618519666227981">"Képernyőn megjelenő kisegítő lehetőségekre vonatkozó parancsválasztó"</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">"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> diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml index 1348f48d127c..bf7ec3897303 100644 --- a/core/res/res/values-hy/strings.xml +++ b/core/res/res/values-hy/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> փաթեթը գցվեց ՍԱՀՄԱՆԱՓԱԿՎԱԾ զամբյուղի մեջ"</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-in/strings.xml b/core/res/res/values-in/strings.xml index 553281b58080..c4ff2e39b215 100644 --- a/core/res/res/values-in/strings.xml +++ b/core/res/res/values-in/strings.xml @@ -2042,8 +2042,12 @@ <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> - <string name="accessibility_system_action_accessibility_button_label" msgid="5941347017132886642">"Pintasan Aksesibilitas di layar"</string> - <string name="accessibility_system_action_accessibility_button_chooser_label" msgid="6973618519666227981">"Pemilih Pintasan Aksesibilitas di layar"</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">"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> diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml index fae36eec1e32..168c63092abb 100644 --- a/core/res/res/values-is/strings.xml +++ b/core/res/res/values-is/strings.xml @@ -2042,8 +2042,12 @@ <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> - <string name="accessibility_system_action_accessibility_button_label" msgid="5941347017132886642">"Flýtileið í aðgengiseiginleika á skjá"</string> - <string name="accessibility_system_action_accessibility_button_chooser_label" msgid="6973618519666227981">"Val um flýtileið í aðgengiseiginleika á skjánum"</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">"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> diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml index f754320ced90..f4794a2d5c22 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -2042,8 +2042,12 @@ <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> - <string name="accessibility_system_action_accessibility_button_label" msgid="5941347017132886642">"Scorciatoia Accessibilità sullo schermo"</string> - <string name="accessibility_system_action_accessibility_button_chooser_label" msgid="6973618519666227981">"Selettore scorciatoia Accessibilità sullo schermo"</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">"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> diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml index b5b527ec8905..c1580da63c12 100644 --- a/core/res/res/values-iw/strings.xml +++ b/core/res/res/values-iw/strings.xml @@ -2110,8 +2110,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-ja/strings.xml b/core/res/res/values-ja/strings.xml index 277207eda9d3..1ba098f13f11 100644 --- a/core/res/res/values-ja/strings.xml +++ b/core/res/res/values-ja/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-ka/strings.xml b/core/res/res/values-ka/strings.xml index f7aa07390ce4..f21668099eb5 100644 --- a/core/res/res/values-ka/strings.xml +++ b/core/res/res/values-ka/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> მოთავსდა კალათაში „შეზღუდული“"</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-kk/strings.xml b/core/res/res/values-kk/strings.xml index 718d2734dcd2..d905d460ed36 100644 --- a/core/res/res/values-kk/strings.xml +++ b/core/res/res/values-kk/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">"Экрандағы Accessibility таңбашасы"</string> - <string name="accessibility_system_action_accessibility_button_chooser_label" msgid="6973618519666227981">"Экрандағы Accessibility таңбашасын таңдау құралы"</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-km/strings.xml b/core/res/res/values-km/strings.xml index d3d1848c0178..4ec4c14e3d23 100644 --- a/core/res/res/values-km/strings.xml +++ b/core/res/res/values-km/strings.xml @@ -2044,8 +2044,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-kn/strings.xml b/core/res/res/values-kn/strings.xml index 508a71da26da..5c8068498373 100644 --- a/core/res/res/values-kn/strings.xml +++ b/core/res/res/values-kn/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> ಅನ್ನು ನಿರ್ಬಂಧಿತ ಬಕೆಟ್ಗೆ ಹಾಕಲಾಗಿದೆ"</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-ko/strings.xml b/core/res/res/values-ko/strings.xml index 66df0559def5..79cd4fe7c8d3 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 c22061b4b5b4..9dc6e4656d2b 100644 --- a/core/res/res/values-ky/strings.xml +++ b/core/res/res/values-ky/strings.xml @@ -1794,7 +1794,7 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Администраторуңуз жаңыртып койгон"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Администраторуңуз жок кылып салган"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"ЖАРАЙТ"</string> - <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Батареянын мөөнөтүн узартуу үчүн, Батареяны үнөмдөгүч режими төмөнкүлөрдү аткарат:\n\n•Түнкү режимди күйгүзөт\n•Фондогу аракеттерди, айрым визуалдык эффекттерди жана \"Окей Google\" сыяктуу башка функцияларды өчүрөт же чектейт\n\n"<annotation id="url">"Кеңири маалымат"</annotation></string> + <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> @@ -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-lo/strings.xml b/core/res/res/values-lo/strings.xml index fbcae03c92e6..cd597600642d 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 b230b42f5c53..e0132e45da0e 100644 --- a/core/res/res/values-lt/strings.xml +++ b/core/res/res/values-lt/strings.xml @@ -2110,8 +2110,12 @@ <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> - <string name="accessibility_system_action_accessibility_button_label" msgid="5941347017132886642">"Ekrano pritaikomumo šaukinys"</string> - <string name="accessibility_system_action_accessibility_button_chooser_label" msgid="6973618519666227981">"Ekrano pritaikomumo šaukinių parinkiklis"</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">"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> diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml index 43890409c37c..eeaf12ffa93d 100644 --- a/core/res/res/values-lv/strings.xml +++ b/core/res/res/values-lv/strings.xml @@ -2076,8 +2076,12 @@ <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> - <string name="accessibility_system_action_accessibility_button_label" msgid="5941347017132886642">"Ekrāna pieejamības saīsne"</string> - <string name="accessibility_system_action_accessibility_button_chooser_label" msgid="6973618519666227981">"Ekrāna pieejamības saīsnes atlasītājs"</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">"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> diff --git a/core/res/res/values-mcc334-mnc020/config.xml b/core/res/res/values-mcc334-mnc020/config.xml index 0970517835b6..c64acc7c29db 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 000000000000..a8a78d5ef3fc --- /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 f3262d66c0c6..7c0cff19cef5 100644 --- a/core/res/res/values-mk/strings.xml +++ b/core/res/res/values-mk/strings.xml @@ -2044,8 +2044,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-ml/strings.xml b/core/res/res/values-ml/strings.xml index 2c99a741a7a5..bd1193eb16ab 100644 --- a/core/res/res/values-ml/strings.xml +++ b/core/res/res/values-ml/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> നിയന്ത്രിത ബക്കറ്റിലേക്ക് നീക്കി"</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-mn/strings.xml b/core/res/res/values-mn/strings.xml index c404bcde9a34..51138a7afe50 100644 --- a/core/res/res/values-mn/strings.xml +++ b/core/res/res/values-mn/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>-г ХЯЗГААРЛАСАН сагс руу орууллаа"</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-mr/strings.xml b/core/res/res/values-mr/strings.xml index 1d894a39b4c6..7943bd47c656 100644 --- a/core/res/res/values-mr/strings.xml +++ b/core/res/res/values-mr/strings.xml @@ -1798,7 +1798,7 @@ <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> @@ -1888,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> @@ -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-ms/strings.xml b/core/res/res/values-ms/strings.xml index 3fe29b10a407..23808b82af08 100644 --- a/core/res/res/values-ms/strings.xml +++ b/core/res/res/values-ms/strings.xml @@ -2042,8 +2042,12 @@ <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> - <string name="accessibility_system_action_accessibility_button_label" msgid="5941347017132886642">"Pintasan Kebolehaksesan Pada Skrin"</string> - <string name="accessibility_system_action_accessibility_button_chooser_label" msgid="6973618519666227981">"Pemilih Pintasan Kebolehaksesan Pada Skrin"</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">"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> diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml index c5e68970307a..f8e409d3abb2 100644 --- a/core/res/res/values-my/strings.xml +++ b/core/res/res/values-my/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> ကို တားမြစ်ထားသော သိမ်းဆည်းမှုအတွင်းသို့ ထည့်ပြီးပါပြီ"</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-nb/strings.xml b/core/res/res/values-nb/strings.xml index 6bd58cf718d1..f4b7ec3b16d5 100644 --- a/core/res/res/values-nb/strings.xml +++ b/core/res/res/values-nb/strings.xml @@ -1794,8 +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> - <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="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> @@ -2042,8 +2042,12 @@ <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> - <string name="accessibility_system_action_accessibility_button_label" msgid="5941347017132886642">"Tilgjengelighetssnarvei på skjermen"</string> - <string name="accessibility_system_action_accessibility_button_chooser_label" msgid="6973618519666227981">"Velger for tilgjengelighetssnarvei på skjermen"</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">"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> diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml index cf6a7eca8617..ba599e84f88d 100644 --- a/core/res/res/values-ne/strings.xml +++ b/core/res/res/values-ne/strings.xml @@ -2048,8 +2048,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-nl/strings.xml b/core/res/res/values-nl/strings.xml index 70c538e0555d..f320e5ddf7d8 100644 --- a/core/res/res/values-nl/strings.xml +++ b/core/res/res/values-nl/strings.xml @@ -2042,8 +2042,12 @@ <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> - <string name="accessibility_system_action_accessibility_button_label" msgid="5941347017132886642">"Snelkoppeling voor toegankelijkheid op scherm"</string> - <string name="accessibility_system_action_accessibility_button_chooser_label" msgid="6973618519666227981">"Kiezer voor snelkoppeling voor toegankelijkheid op scherm"</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">"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> diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml index 984c38d65dea..28f552ec4200 100644 --- a/core/res/res/values-or/strings.xml +++ b/core/res/res/values-or/strings.xml @@ -1798,7 +1798,7 @@ <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> @@ -1888,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> @@ -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-pa/strings.xml b/core/res/res/values-pa/strings.xml index 6e7eff169472..e0c6056d493b 100644 --- a/core/res/res/values-pa/strings.xml +++ b/core/res/res/values-pa/strings.xml @@ -1888,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> @@ -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-pl/strings.xml b/core/res/res/values-pl/strings.xml index 7d4dd03522a7..c12c9ae3f352 100644 --- a/core/res/res/values-pl/strings.xml +++ b/core/res/res/values-pl/strings.xml @@ -2110,8 +2110,12 @@ <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> - <string name="accessibility_system_action_accessibility_button_label" msgid="5941347017132886642">"Ekranowy skrót ułatwień dostępu"</string> - <string name="accessibility_system_action_accessibility_button_chooser_label" msgid="6973618519666227981">"Wybieranie ekranowego skrótu ułatwień dostępu"</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">"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> diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml index fcd4e347dc44..dbd69a192940 100644 --- a/core/res/res/values-pt-rBR/strings.xml +++ b/core/res/res/values-pt-rBR/strings.xml @@ -2042,8 +2042,12 @@ <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> - <string name="accessibility_system_action_accessibility_button_label" msgid="5941347017132886642">"Atalho de acessibilidade na tela"</string> - <string name="accessibility_system_action_accessibility_button_chooser_label" msgid="6973618519666227981">"Seletor de atalho de acessibilidade na tela"</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">"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> diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml index 832453c8e717..6bd1dfa69bea 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> @@ -1796,7 +1796,7 @@ <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</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 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="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"> @@ -1875,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> @@ -1884,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> @@ -1893,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> @@ -1906,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> @@ -1976,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> @@ -2008,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> @@ -2033,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> @@ -2042,9 +2042,13 @@ <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> - <string name="accessibility_system_action_accessibility_button_label" msgid="5941347017132886642">"Atalho de acessibilidade no ecrã"</string> - <string name="accessibility_system_action_accessibility_button_chooser_label" msgid="6973618519666227981">"Selecionador de atalhos de acessibilidade no ecrã"</string> - <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_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">"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> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"enviou uma imagem"</string> diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml index fcd4e347dc44..dbd69a192940 100644 --- a/core/res/res/values-pt/strings.xml +++ b/core/res/res/values-pt/strings.xml @@ -2042,8 +2042,12 @@ <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> - <string name="accessibility_system_action_accessibility_button_label" msgid="5941347017132886642">"Atalho de acessibilidade na tela"</string> - <string name="accessibility_system_action_accessibility_button_chooser_label" msgid="6973618519666227981">"Seletor de atalho de acessibilidade na tela"</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">"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> diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml index 7dc8f3363c0d..02e3fdaaf1b8 100644 --- a/core/res/res/values-ro/strings.xml +++ b/core/res/res/values-ro/strings.xml @@ -1817,8 +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> - <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Pentru a prelungi autonomia bateriei, Economisirea bateriei:\n\n•·activează tema întunecată;\n•·activează 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 prelungi autonomia bateriei, Economisirea bateriei:\n\n• activează tema întunecată;\n• activează sau restricționează activitatea în fundal, unele efecte vizuale și alte funcții, cum ar fi „Ok Google”."</string> + <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> @@ -2076,8 +2076,12 @@ <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> - <string name="accessibility_system_action_accessibility_button_label" msgid="5941347017132886642">"Comandă rapidă de accesibilitate de pe ecran"</string> - <string name="accessibility_system_action_accessibility_button_chooser_label" msgid="6973618519666227981">"Selector de comenzi rapide de accesibilitate de pe ecran"</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">"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> diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index ad0797eeb540..b8047549a55e 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -2110,8 +2110,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-si/strings.xml b/core/res/res/values-si/strings.xml index 2e0c919aecda..103bc392d252 100644 --- a/core/res/res/values-si/strings.xml +++ b/core/res/res/values-si/strings.xml @@ -2044,8 +2044,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-sk/strings.xml b/core/res/res/values-sk/strings.xml index 887a66e36527..485ee1126666 100644 --- a/core/res/res/values-sk/strings.xml +++ b/core/res/res/values-sk/strings.xml @@ -2110,8 +2110,12 @@ <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> - <string name="accessibility_system_action_accessibility_button_label" msgid="5941347017132886642">"Skratka dostupnosti na obrazovke"</string> - <string name="accessibility_system_action_accessibility_button_chooser_label" msgid="6973618519666227981">"Výber skratky dostupnosti na obrazovke"</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">"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> diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml index fc9ada233272..b8bb8afe30a6 100644 --- a/core/res/res/values-sl/strings.xml +++ b/core/res/res/values-sl/strings.xml @@ -2110,8 +2110,12 @@ <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> - <string name="accessibility_system_action_accessibility_button_label" msgid="5941347017132886642">"Zaslonska bližnjica funkcij za ljudi s posebnimi potrebami"</string> - <string name="accessibility_system_action_accessibility_button_chooser_label" msgid="6973618519666227981">"Izbirnik zaslonske bližnjice funkcij za ljudi s posebnimi potrebami"</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">"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> diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml index fd6482e31e84..55f006ea8c6e 100644 --- a/core/res/res/values-sq/strings.xml +++ b/core/res/res/values-sq/strings.xml @@ -2042,8 +2042,12 @@ <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> - <string name="accessibility_system_action_accessibility_button_label" msgid="5941347017132886642">"Shkurtorja e qasshmërisë në ekran"</string> - <string name="accessibility_system_action_accessibility_button_chooser_label" msgid="6973618519666227981">"Zgjedhësi i shkurtores së qasshmërisë në ekran"</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">"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> diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml index 19d87255ee04..d149e27cc35b 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,8 +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> - <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="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> @@ -1885,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> @@ -1920,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> @@ -1930,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> @@ -2076,8 +2076,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> @@ -2090,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 af9ddfec3c20..bb268cce256a 100644 --- a/core/res/res/values-sv/strings.xml +++ b/core/res/res/values-sv/strings.xml @@ -2042,8 +2042,12 @@ <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> - <string name="accessibility_system_action_accessibility_button_label" msgid="5941347017132886642">"Tillgänglighetsgenväg på skärmen"</string> - <string name="accessibility_system_action_accessibility_button_chooser_label" msgid="6973618519666227981">"Valfunktion för tillgänglighetsgenväg på skärmen"</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">"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> diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml index a31be6f4abbb..4f9376c02bd0 100644 --- a/core/res/res/values-sw/strings.xml +++ b/core/res/res/values-sw/strings.xml @@ -1889,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> @@ -2042,12 +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> - <string name="accessibility_system_action_accessibility_button_label" msgid="5941347017132886642">"Njia ya Mkato ya Ufikivu kwenye Skrini"</string> - <string name="accessibility_system_action_accessibility_button_chooser_label" msgid="6973618519666227981">"Kichagua Njia ya Mkato ya Ufikivu kwenye Skrini"</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">"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> - <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"imetuma picha"</string> + <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 591c8596d411..97b2afd095e7 100644 --- a/core/res/res/values-ta/strings.xml +++ b/core/res/res/values-ta/strings.xml @@ -2044,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 27635cd7e7c6..1b1d43f3385d 100644 --- a/core/res/res/values-te/strings.xml +++ b/core/res/res/values-te/strings.xml @@ -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•బ్యాక్గ్రౌండ్ యాక్టివిటీ, కొన్ని విజువల్ ఎఫెక్ట్లతో పాటు “Ok Google” వంటి ఇతర ఫీచర్లను ఆఫ్ చేస్తుంది లేదా పరిమితం చేస్తుంది\n\n"<annotation id="url">"మరింత తెలుసుకోండి"</annotation></string> - <string name="battery_saver_description" msgid="8587408568232177204">"బ్యాటరీ జీవితకాలాన్ని పెంచడానికి, బ్యాటరీ సేవర్ వీటిని చేస్తుంది:\n\n•ముదురు రంగు థీమ్ను ఆన్ చేస్తుంది\n•బ్యాక్గ్రౌండ్ యాక్టివిటీ, కొన్ని విజువల్ ఎఫెక్ట్లతో పాటు “Ok 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> @@ -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-th/strings.xml b/core/res/res/values-th/strings.xml index b298dbd2487c..80c7a59e91f8 100644 --- a/core/res/res/values-th/strings.xml +++ b/core/res/res/values-th/strings.xml @@ -1795,7 +1795,7 @@ <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•ปิดหรือจำกัดกิจกรรมในเบื้องหลัง เอฟเฟกต์ภาพบางอย่าง และฟีเจอร์อื่นๆ อย่างเช่น “Ok Google”\n\n"<annotation id="url">"ดูข้อมูลเพิ่มเติม"</annotation></string> - <string name="battery_saver_description" msgid="8587408568232177204">"โหมดประหยัดแบตเตอรี่จะดำเนินการดังต่อไปนี้เพื่อยืดอายุการใช้งานแบตเตอรี่\n\n•·เปิดธีมมืด\n•ปิดหรือจำกัดกิจกรรมในเบื้องหลัง เอฟเฟกต์ภาพบางอย่าง และฟีเจอร์อื่นๆ อย่างเช่น “Ok Google”"</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> @@ -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-tl/strings.xml b/core/res/res/values-tl/strings.xml index ee41ca9386d4..e1e9ca840d69 100644 --- a/core/res/res/values-tl/strings.xml +++ b/core/res/res/values-tl/strings.xml @@ -2042,8 +2042,12 @@ <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> - <string name="accessibility_system_action_accessibility_button_label" msgid="5941347017132886642">"Shortcut ng Accessibility sa Screen"</string> - <string name="accessibility_system_action_accessibility_button_chooser_label" msgid="6973618519666227981">"Tagapili ng Shortcut ng Accessibility sa Screen"</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">"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> diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml index bae1bd7ac983..05984a03bde8 100644 --- a/core/res/res/values-tr/strings.xml +++ b/core/res/res/values-tr/strings.xml @@ -2042,8 +2042,12 @@ <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> - <string name="accessibility_system_action_accessibility_button_label" msgid="5941347017132886642">"Ekran Erişilebilirlik Kısayolu"</string> - <string name="accessibility_system_action_accessibility_button_chooser_label" msgid="6973618519666227981">"Ekran Erişilebilirlik Kısayol Seçici"</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> 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> diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml index ad50bfa10610..fe373a1a8b15 100644 --- a/core/res/res/values-uk/strings.xml +++ b/core/res/res/values-uk/strings.xml @@ -2110,8 +2110,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-ur/strings.xml b/core/res/res/values-ur/strings.xml index b2f55cf316e0..f2ed25089684 100644 --- a/core/res/res/values-ur/strings.xml +++ b/core/res/res/values-ur/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> کو پابند کردہ بکٹ میں رکھ دیا گیا ہے"</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-uz/strings.xml b/core/res/res/values-uz/strings.xml index 0df6c1b9c365..e0725578f648 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> @@ -2042,8 +2042,12 @@ <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> - <string name="accessibility_system_action_accessibility_button_label" msgid="5941347017132886642">"Ekranda tezkor ishga tushirish"</string> - <string name="accessibility_system_action_accessibility_button_chooser_label" msgid="6973618519666227981">"Ekranda tezkor ishga tushirishni tanlagich"</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> 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> diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml index 54f9b78c9922..8579414dcfc8 100644 --- a/core/res/res/values-vi/strings.xml +++ b/core/res/res/values-vi/strings.xml @@ -2042,8 +2042,12 @@ <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> - <string name="accessibility_system_action_accessibility_button_label" msgid="5941347017132886642">"Phím tắt ảo hỗ trợ tiếp cận"</string> - <string name="accessibility_system_action_accessibility_button_chooser_label" msgid="6973618519666227981">"Nút chọn phím tắt ảo hỗ trợ tiếp cận"</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">"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> diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index a89ac8a66765..7b3ca7663d1a 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/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> 已被放入受限存储分区"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> @@ -2063,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 7e5caf95684a..30a596ae1917 100644 --- a/core/res/res/values-zh-rHK/strings.xml +++ b/core/res/res/values-zh-rHK/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> 已納入受限制的儲存區"</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-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml index 076c37478e8b..ac5ebaa86c1b 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/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>」移入受限制的值區"</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-zu/strings.xml b/core/res/res/values-zu/strings.xml index 13be23e01cf8..32a31f72336f 100644 --- a/core/res/res/values-zu/strings.xml +++ b/core/res/res/values-zu/strings.xml @@ -2042,8 +2042,12 @@ <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> - <string name="accessibility_system_action_accessibility_button_label" msgid="5941347017132886642">"Isinqamuleli sokufinyeleleka kusikrini"</string> - <string name="accessibility_system_action_accessibility_button_chooser_label" msgid="6973618519666227981">"Isikhethi sesinqamuleli sokufinyeleleka kusikrini"</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">"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> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index b91d35b604ca..65fa3fa1ee1d 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 @@ -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/strings.xml b/core/res/res/values/strings.xml index 33dd81dca33e..35a7857b839f 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 @@ ul.</string> <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 bcce1f05f0dd..f920083f5cb3 100644 --- a/core/res/res/values/styles.xml +++ b/core/res/res/values/styles.xml @@ -248,12 +248,6 @@ please see styles_device_defaults.xml. <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 3dc3b0b0acbe..3ac2dc54c00a 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1580,7 +1580,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" /> @@ -1825,6 +1824,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" /> @@ -3447,7 +3449,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" /> @@ -3844,8 +3845,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" /> @@ -3999,4 +4001,11 @@ <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 88f9fc2199e5..6e2995de0fe1 100644 --- a/core/res/res/values/themes.xml +++ b/core/res/res/values/themes.xml @@ -704,6 +704,7 @@ please see themes_device_defaults.xml. <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/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java index 567552f66b35..6720ed6b7bf9 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.IntentSender; 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 @@ public class PackageManagerTests extends AndroidTestCase { 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 @@ public class PackageManagerTests extends AndroidTestCase { 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 @@ public class PackageManagerTests extends AndroidTestCase { 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 @@ public class PackageManagerTests extends AndroidTestCase { 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 @@ public class PackageManagerTests extends AndroidTestCase { } } - 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 @@ public class PackageManagerTests extends AndroidTestCase { 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 @@ public class PackageManagerTests extends AndroidTestCase { 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 @@ public class PackageManagerTests extends AndroidTestCase { 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 class PackageManagerTests extends AndroidTestCase { 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 @@ public class PackageManagerTests extends AndroidTestCase { } 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 @@ public class PackageManagerTests extends AndroidTestCase { 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 @@ public class PackageManagerTests extends AndroidTestCase { 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 @@ public class PackageManagerTests extends AndroidTestCase { // 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 @@ public class PackageManagerTests extends AndroidTestCase { 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 @@ public class PackageManagerTests extends AndroidTestCase { 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 @@ public class PackageManagerTests extends AndroidTestCase { 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 @@ public class PackageManagerTests extends AndroidTestCase { 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 @@ public class PackageManagerTests extends AndroidTestCase { // **: 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 @@ public class PackageManagerTests extends AndroidTestCase { 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 @@ public class PackageManagerTests extends AndroidTestCase { 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 @@ public class PackageManagerTests extends AndroidTestCase { 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 @@ public class PackageManagerTests extends AndroidTestCase { // **: 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 @@ public class PackageManagerTests extends AndroidTestCase { 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 @@ public class PackageManagerTests extends AndroidTestCase { failStr(e.getMessage()); } finally { if (cleanUp) { - cleanUpInstall(pkg1.packageName); + cleanUpInstall(pkg1.getPackageName()); } } return null; @@ -2460,16 +2463,16 @@ public class PackageManagerTests extends AndroidTestCase { 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 @@ public class PackageManagerTests extends AndroidTestCase { 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,14 @@ public class PackageManagerTests extends AndroidTestCase { } else { installFromRawResource(apk2Name, apk2, 0, false, false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED); - int match = mContext.getPackageManager().checkSignatures(pkg1.packageName, - pkg2.packageName); + int match = mContext.getPackageManager().checkSignatures(pkg1.getPackageName(), + pkg2.getPackageName()); assertEquals(expMatchResult, match); } } finally { if (cleanUp) { - cleanUpInstall(pkg1.packageName); - cleanUpInstall(pkg2.packageName); + cleanUpInstall(pkg1.getPackageName()); + cleanUpInstall(pkg2.getPackageName()); } } } @@ -2618,15 +2621,15 @@ public class PackageManagerTests extends AndroidTestCase { 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 +2834,8 @@ public class PackageManagerTests extends AndroidTestCase { 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 164c372768c0..bfcf52af80bf 100644 --- a/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java +++ b/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java @@ -100,12 +100,12 @@ public class ImeInsetsSourceConsumerTest { // 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 cc85332590ba..d4c256972b28 100644 --- a/core/tests/coretests/src/android/view/InsetsControllerTest.java +++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java @@ -245,14 +245,14 @@ public class InsetsControllerTest { 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 @@ public class InsetsControllerTest { 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 @@ public class InsetsControllerTest { 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 @@ public class InsetsControllerTest { 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 @@ public class InsetsControllerTest { 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 @@ public class InsetsControllerTest { 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 @@ public class InsetsControllerTest { 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 @@ public class InsetsControllerTest { 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 @@ public class InsetsControllerTest { 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 @@ public class InsetsControllerTest { // 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 @@ public class InsetsControllerTest { 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 @@ public class InsetsControllerTest { // 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 @@ public class InsetsControllerTest { 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 @@ public class InsetsControllerTest { 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 @@ public class InsetsControllerTest { 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/com/android/internal/app/ChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java index 80fb35813009..e23a3cad914b 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 @@ public class ChooserActivityTest { 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 @@ public class ChooserActivityTest { 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 @@ public class ChooserActivityTest { 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/data/etc/car/com.google.android.car.kitchensink.xml b/data/etc/car/com.google.android.car.kitchensink.xml index efe658a80233..7292e0796bf5 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 000000000000..0214361717ce --- /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 000000000000..098f4bfa74ac --- /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 000000000000..48123abd26cb --- /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 000000000000..232cf3f0d677 --- /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 000000000000..46f0fb2e534c --- /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/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java index 412b43e6a582..a112bdd0ce03 100644 --- a/location/java/android/location/LocationManager.java +++ b/location/java/android/location/LocationManager.java @@ -2954,10 +2954,10 @@ public class LocationManager { @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 @@ public class LocationManager { @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 @@ public class LocationManager { @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 @@ public class LocationManager { @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 @@ public class LocationManager { @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/AudioMetadata.java b/media/java/android/media/AudioMetadata.java index c91ff0d099cf..ff9fd4187272 100644 --- a/media/java/android/media/AudioMetadata.java +++ b/media/java/android/media/AudioMetadata.java @@ -166,10 +166,25 @@ public final class AudioMetadata { * * 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 @@ public final class AudioMetadata { 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 @@ public final class AudioMetadata { 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/MediaRouter2Manager.java b/media/java/android/media/MediaRouter2Manager.java index 5d61dd06c792..e3c7336905d1 100644 --- a/media/java/android/media/MediaRouter2Manager.java +++ b/media/java/android/media/MediaRouter2Manager.java @@ -24,7 +24,6 @@ import android.annotation.Nullable; 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 final class MediaRouter2Manager { 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 @@ public final class MediaRouter2Manager { } /** + * 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 @@ public final class MediaRouter2Manager { } /** + * 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 @@ public final class MediaRouter2Manager { /** * 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,22 +624,11 @@ public final class MediaRouter2Manager { } 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 @@ -782,153 +819,32 @@ public final class MediaRouter2Manager { } } - private List<MediaRoute2Info> getRoutesWithIds(List<String> routeIds) { - synchronized (sLock) { - return routeIds.stream().map(mRoutes::get) - .filter(Objects::nonNull) - .collect(Collectors.toList()); + private boolean areSessionsMatched(MediaController mediaController, + RoutingSessionInfo sessionInfo) { + MediaController.PlaybackInfo playbackInfo = mediaController.getPlaybackInfo(); + if (playbackInfo == null) { + return false; } - } - //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; + String volumeControlId = playbackInfo.getVolumeControlId(); + if (volumeControlId == null) { + return false; } - /** - * Releases the session - */ - public void release() { - synchronized (mControllerLock) { - releaseSession(mSessionInfo); - } - } - - /** - * Gets the ID of the session - */ - @NonNull - public String getSessionId() { - synchronized (mControllerLock) { - return mSessionInfo.getId(); - } - } - - /** - * 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); + if (TextUtils.equals(volumeControlId, sessionInfo.getId())) { + return true; } + // Workaround for provider not being able to know the unique session ID. + return TextUtils.equals(volumeControlId, sessionInfo.getOriginalId()) + && TextUtils.equals(mediaController.getPackageName(), + sessionInfo.getOwnerPackageName()); + } - /** - * Gets the session info of the session - * - * @hide - */ - @NonNull - public RoutingSessionInfo getSessionInfo() { - synchronized (mControllerLock) { - return mSessionInfo; - } + private List<MediaRoute2Info> getRoutesWithIds(List<String> routeIds) { + synchronized (sLock) { + return routeIds.stream().map(mRoutes::get) + .filter(Objects::nonNull) + .collect(Collectors.toList()); } } @@ -976,16 +892,6 @@ public final class MediaRouter2Manager { 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 608e29a7a6ca..edf1fc58ecf5 100644 --- a/media/java/android/media/RoutingSessionInfo.java +++ b/media/java/android/media/RoutingSessionInfo.java @@ -50,6 +50,7 @@ public final class RoutingSessionInfo implements Parcelable { final String mId; final CharSequence mName; + final String mOwnerPackageName; final String mClientPackageName; @Nullable final String mProviderId; @@ -71,6 +72,7 @@ public final class RoutingSessionInfo implements Parcelable { mId = builder.mId; mName = builder.mName; + mOwnerPackageName = builder.mOwnerPackageName; mClientPackageName = builder.mClientPackageName; mProviderId = builder.mProviderId; @@ -96,6 +98,7 @@ public final class RoutingSessionInfo implements Parcelable { 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 @@ public final class RoutingSessionInfo implements Parcelable { } /** + * 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 final class RoutingSessionInfo implements Parcelable { 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 @@ public final class RoutingSessionInfo implements Parcelable { 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 @@ public final class RoutingSessionInfo implements Parcelable { @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 @@ public final class RoutingSessionInfo implements Parcelable { // 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 @@ public final class RoutingSessionInfo implements Parcelable { } /** + * 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 f058a02ceb1e..e701055c2894 100644 --- a/media/java/android/media/tv/TvInputManager.java +++ b/media/java/android/media/tv/TvInputManager.java @@ -1805,7 +1805,7 @@ public final class TvInputManager { 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 @@ public final class TvInputManager { 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 598ff8f3f075..28f1ac916690 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 @@ public final class ResourceClientProfile implements Parcelable { * 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 @@ public final class ResourceClientProfile implements Parcelable { * * @return the value of the tv input session id. */ - @NonNull + @Nullable public String getTvInputSessionId() { return mTvInputSessionId; } 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 a169c0d7c7f9..d48b10a81a18 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 @@ public class BluetoothMidiEncoderTest { } 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 @@ public class BluetoothMidiEncoderTest { assertEquals(expectedRow[k], actualRow[k]); } } + assertEquals(expected.length, actualRows.length); } void writeComplete() { @@ -115,8 +123,11 @@ public class BluetoothMidiEncoderTest { (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 @@ public class BluetoothMidiEncoderTest { (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 @@ public class BluetoothMidiEncoderTest { 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 @@ public class BluetoothMidiEncoderTest { 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/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java index f066bf589b64..ab7bf5e2eac0 100644 --- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java +++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java @@ -27,6 +27,7 @@ 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.dock.DockManager; @@ -47,6 +48,7 @@ import com.android.systemui.statusbar.phone.HeadsUpManagerPhone; 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; @@ -156,4 +158,8 @@ public abstract class CarSystemUIModule { @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 af8ddb6a8180..236a6a451ea4 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 @@ import javax.inject.Singleton; @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 @@ public class HvacController { 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 @@ public class HvacController { 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/navigationbar/CarNavigationBar.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBar.java index fcc8c8cddeb1..893efdc0991c 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.R; 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 com.android.systemui.statusbar.policy.KeyguardStateController; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.util.concurrent.Executor; import javax.inject.Inject; @@ -74,7 +75,7 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks 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 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks 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 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks AutoHideController autoHideController, ButtonSelectionStateListener buttonSelectionStateListener, @Main Handler mainHandler, - @Background Handler bgHandler, + @UiBackground Executor uiBgExecutor, IStatusBarService barService, Lazy<KeyguardStateController> keyguardStateControllerLazy, ButtonSelectionStateController buttonSelectionStateController, @@ -136,7 +139,7 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks mAutoHideController = autoHideController; mButtonSelectionStateListener = buttonSelectionStateListener; mMainHandler = mainHandler; - mBgHandler = bgHandler; + mUiBgExecutor = uiBgExecutor; mBarService = barService; mKeyguardStateControllerLazy = keyguardStateControllerLazy; mButtonSelectionStateController = buttonSelectionStateController; @@ -232,7 +235,7 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks 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 9e194fb49d3a..288e5cf13c2e 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 @@ public class CarNavigationBarController { } /** - * Hides all navigation bars. + * Hides all system bars. */ public void hideBars() { if (mTopView != null) { @@ -85,7 +85,7 @@ public class CarNavigationBarController { } /** - * 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 20fcca0d0220..aeb1d39599db 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 android.widget.FrameLayout; 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 @@ public class CarHeadsUpNotificationSystemContainer implements CarHeadsUpNotifica 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 cb9539ad5b1d..1738091d14c9 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 @@ public class NotificationPanelViewController extends OverlayPanelViewController 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 @@ public class NotificationPanelViewController extends OverlayPanelViewController + " percentage"); } mBackgroundAlphaDiff = finalBackgroundAlpha - mInitialBackgroundAlpha; + + mEnableHeadsUpNotificationWhenNotificationShadeOpen = mResources.getBoolean( + com.android.car.notification.R.bool + .config_enableHeadsUpNotificationWhenNotificationShadeOpen); } @Override @@ -151,6 +156,16 @@ public class NotificationPanelViewController extends OverlayPanelViewController 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 8f52638afdf1..41349b284147 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.navigationbar.CarNavigationBarController; 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 @@ public abstract class NotificationPanelViewMediator implements OverlayViewMediat 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 000000000000..a4230032858e --- /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 0fe985684543..45808a8a0b3e 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 @@ public abstract class OverlayPanelViewController extends OverlayViewController { } 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 87f20208476b..30e26578bd73 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 @@ public class OverlayViewController { mOverlayViewGlobalStateController.hideView(/* viewController= */ this, this::hide); } - /** * Inflate layout owned by controller. */ @@ -72,7 +71,7 @@ public class OverlayViewController { } /** - * 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 @@ public class OverlayViewController { 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 290505f5042a..70260b0d4cef 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 @@ import javax.inject.Singleton; */ @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 @@ public class OverlayViewGlobalStateController { mSystemUIOverlayWindowController = systemUIOverlayWindowController; mSystemUIOverlayWindowController.attach(); mCarNavigationBarController = carNavigationBarController; - mShownSet = new HashSet<>(); + mZOrderMap = new HashMap<>(); + mZOrderVisibleSortedMap = new TreeMap<>(); } /** @@ -66,51 +76,127 @@ public class OverlayViewGlobalStateController { } /** - * 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(); + public void showView(OverlayPanelViewController panelViewController) { + showView(panelViewController, /* show= */ null); + } + + /** + * Show content in Overlay Window using {@link OverlayViewController}. + */ + public void showView(OverlayViewController viewController, @Nullable Runnable show) { + debugLog(); + if (mZOrderVisibleSortedMap.isEmpty()) { setWindowVisible(true); } + if (!(viewController instanceof OverlayPanelViewController)) { + inflateView(viewController); + } - inflateView(viewController); + if (show != null) { + show.run(); + } - show.run(); - mShownSet.add(viewController.getClass().getName()); + 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. + * Hide content in Overlay Window using {@link OverlayViewController}. */ - public void hideView(OverlayViewController viewController, Runnable hide) { + 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(); + } + + private void refreshHighestZOrderWhenHidingView(OverlayViewController viewController) { + if (mZOrderVisibleSortedMap.isEmpty()) { + mHighestZOrder = null; + return; + } + if (!mHighestZOrder.equals(viewController)) { + return; + } + + mHighestZOrder = mZOrderVisibleSortedMap.get(mZOrderVisibleSortedMap.lastKey()); } - /** Sets the window visibility state. */ - public void setWindowVisible(boolean expanded) { - mSystemUIOverlayWindowController.setWindowVisible(expanded); + 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 @@ public class OverlayViewGlobalStateController { 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 @@ public class OverlayViewGlobalStateController { 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 e1918ceeaea4..484aa63e8bda 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 @@ package com.android.systemui.car.window; 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 @@ import dagger.multibindings.IntoMap; @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 000000000000..03fe0e4fcf2e --- /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 a2192af14758..1b4621f1c279 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.os.Handler; 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.SysuiTestCase; 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 com.android.systemui.statusbar.policy.KeyguardStateController; 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 @@ import dagger.Lazy; 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 @@ public class CarKeyguardViewControllerTest extends SysuiTestCase { 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 @@ public class CarKeyguardViewControllerTest extends SysuiTestCase { 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 @@ public class CarKeyguardViewControllerTest extends SysuiTestCase { 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 @@ public class CarKeyguardViewControllerTest extends SysuiTestCase { 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 c555f64825d8..77eecaccaaa4 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 android.view.InsetsState.ITYPE_STATUS_BAR; 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.AutoHideController; 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 @@ public class CarNavigationBarTest extends SysuiTestCase { private CarNavigationBar mCarNavigationBar; private TestableResources mTestableResources; private Handler mHandler; - private Handler mBackgroundHandler; @Mock private CarNavigationBarController mCarNavigationBarController; @@ -81,16 +87,38 @@ public class CarNavigationBarTest extends SysuiTestCase { @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 @@ public class CarNavigationBarTest extends SysuiTestCase { verify(mDeviceProvisionedController).addCallback(deviceProvisionedCallbackCaptor.capture()); deviceProvisionedCallbackCaptor.getValue().onUserSwitched(); - waitForIdleSync(mBackgroundHandler); + waitForIdleSync(mHandler); verify(mButtonSelectionStateListener).onTaskStackChanged(); } @@ -128,7 +156,7 @@ public class CarNavigationBarTest extends SysuiTestCase { verify(mDeviceProvisionedController).addCallback(deviceProvisionedCallbackCaptor.capture()); deviceProvisionedCallbackCaptor.getValue().onUserSwitched(); - waitForIdleSync(mBackgroundHandler); + waitForIdleSync(mHandler); verify(mCarNavigationBarController).showAllKeyguardButtons(false); } @@ -147,12 +175,12 @@ public class CarNavigationBarTest extends SysuiTestCase { 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 6ac72a681bfe..ccaeb458fe54 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 android.view.WindowManager; 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 @@ import org.mockito.MockitoAnnotations; @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 @@ public class CarHeadsUpNotificationSystemContainerTest extends SysuiTestCase { @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, - testableResources.getResources(), mCarDeviceProvisionedController, mWindowManager, - () -> mNotificationPanelViewController); - - testableResources.addOverride( - R.bool.config_enableHeadsUpNotificationWhenNotificationShadeOpen, true); - - mOverrideEnabledController = new CarHeadsUpNotificationSystemContainer(mContext, + mCarHeadsUpNotificationSystemContainer = 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 8d705a8cca1f..45a05ac69bd7 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 @@ public class OverlayPanelViewControllerTest extends SysuiTestCase { mOverlayPanelViewController.setPanelVisible(true); - verify(mOverlayViewGlobalStateController).setWindowVisible(true); + verify(mOverlayViewGlobalStateController).showView(mOverlayPanelViewController); } @Test @@ -349,7 +349,7 @@ public class OverlayPanelViewControllerTest extends SysuiTestCase { mOverlayPanelViewController.setPanelVisible(true); - verify(mOverlayViewGlobalStateController, never()).setWindowVisible(true); + verify(mOverlayViewGlobalStateController, never()).showView(mOverlayPanelViewController); } @Test @@ -377,7 +377,7 @@ public class OverlayPanelViewControllerTest extends SysuiTestCase { mOverlayPanelViewController.setPanelVisible(false); - verify(mOverlayViewGlobalStateController).setWindowVisible(false); + verify(mOverlayViewGlobalStateController).hideView(mOverlayPanelViewController); } @Test @@ -387,7 +387,7 @@ public class OverlayPanelViewControllerTest extends SysuiTestCase { mOverlayPanelViewController.setPanelVisible(false); - verify(mOverlayViewGlobalStateController, never()).setWindowVisible(false); + verify(mOverlayViewGlobalStateController, never()).hideView(mOverlayPanelViewController); } @Test @@ -428,10 +428,6 @@ public class OverlayPanelViewControllerTest extends SysuiTestCase { 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 @@ public class OverlayPanelViewControllerTest extends SysuiTestCase { 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 25dd4f502fb7..9e6e616e3ccf 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 static org.mockito.Mockito.when; 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 @@ public class OverlayViewGlobalStateControllerTest extends SysuiTestCase { @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 class OverlayViewGlobalStateControllerTest extends SysuiTestCase { 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 @@ public class OverlayViewGlobalStateControllerTest extends SysuiTestCase { } @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(mOverlayViewController1, mRunnable); + + assertThat(mOverlayViewGlobalStateController.mHighestZOrder).isEqualTo( + mOverlayViewController1); + } + + @Test + public void showView_nothingAlreadyShown_newHighestZOrder_isVisible() { + setupOverlayViewController1(); + + 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(mOverlayViewController, mRunnable); + mOverlayViewGlobalStateController.showView(mOverlayViewController2, mRunnable); - verify(mCarNavigationBarController, never()).hideBars(); + assertThat(mOverlayViewGlobalStateController.mHighestZOrder).isEqualTo( + mOverlayViewController2); } @Test - public void showView_somethingAlreadyShown_windowIsExpanded() { - mOverlayViewGlobalStateController.mShownSet.add(MOCK_OVERLAY_VIEW_CONTROLLER_NAME); + public void showView_newHighestZOrder_shouldShowNavBarFalse_navigationBarsHidden() { + setupOverlayViewController1(); + setOverlayViewControllerAsShowing(mOverlayViewController1); + setupOverlayViewController2(); + when(mOverlayViewController2.shouldShowNavigationBar()).thenReturn(false); + + mOverlayViewGlobalStateController.showView(mOverlayViewController2, mRunnable); - mOverlayViewGlobalStateController.showView(mOverlayViewController, 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_showRunnableCalled() { - mOverlayViewGlobalStateController.showView(mOverlayViewController, mRunnable); + public void showView_panelViewController_inflateViewControllerNotCalled() { + setupOverlayPanelViewController(); - verify(mRunnable).run(); + mOverlayViewGlobalStateController.showView(mOverlayPanelViewController, mRunnable); + + verify(mOverlayPanelViewController, never()).inflate(mBaseLayout); + verify(mOverlayPanelViewController, never()).isInflated(); } @Test - public void showView_overlayViewControllerAddedToShownSet() { - mOverlayViewGlobalStateController.showView(mOverlayViewController, mRunnable); + public void showView_showRunnableCalled() { + setupOverlayViewController1(); + + mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable); - assertThat(mOverlayViewGlobalStateController.mShownSet.contains( - mOverlayViewController.getClass().getName())).isTrue(); + verify(mRunnable).run(); } @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_noHighestZOrder() { + setupOverlayViewController1(); + setOverlayViewControllerAsShowing(mOverlayViewController1); + + mOverlayViewGlobalStateController.hideView(mOverlayViewController1, mRunnable); + + assertThat(mOverlayViewGlobalStateController.mHighestZOrder).isNull(); + } + + @Test public void hideView_viewControllerOnlyShown_nothingShown() { - when(mOverlayViewController.isInflated()).thenReturn(true); - mOverlayViewGlobalStateController.mShownSet.add( - mOverlayViewController.getClass().getName()); + setupOverlayViewController1(); + setOverlayViewControllerAsShowing(mOverlayViewController1); + + mOverlayViewGlobalStateController.hideView(mOverlayViewController1, mRunnable); + + 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); - mOverlayViewGlobalStateController.hideView(mOverlayViewController, mRunnable); + verify(mCarNavigationBarController).showBars(); + } + + @Test + public void hideView_oldHighestZOrder() { + setupOverlayViewController1(); + setOverlayViewControllerAsShowing(mOverlayViewController1); + setupOverlayViewController2(); + setOverlayViewControllerAsShowing(mOverlayViewController2); - assertThat(mOverlayViewGlobalStateController.mShownSet.isEmpty()).isTrue(); + mOverlayViewGlobalStateController.hideView(mOverlayViewController1, mRunnable); + + assertThat(mOverlayViewGlobalStateController.mHighestZOrder).isEqualTo( + mOverlayViewController2); } @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_oldHighestZOrder_shouldShowNavBarFalse_navigationBarHidden() { + setupOverlayViewController1(); + setOverlayViewControllerAsShowing(mOverlayViewController1); + setupOverlayViewController2(); + setOverlayViewControllerAsShowing(mOverlayViewController2); + when(mOverlayViewController2.shouldShowNavigationBar()).thenReturn(false); - mOverlayViewGlobalStateController.hideView(mOverlayViewController, mRunnable); + mOverlayViewGlobalStateController.hideView(mOverlayViewController1, mRunnable); - verify(mCarNavigationBarController, never()).showBars(); + 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(mOverlayViewController2, never()).inflate(mBaseLayout); + } + + private void setupOverlayViewController1() { + setupOverlayViewController(mOverlayViewController1, R.id.overlay_view_controller_stub_1, + R.id.overlay_view_controller_1); + } - verify(mOverlayViewController, never()).inflate(mBaseLayout); + 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 Binary files differindex 7f5c94891473..e153c910d10a 100644 --- a/packages/CtsShim/apk/arm/CtsShim.apk +++ b/packages/CtsShim/apk/arm/CtsShim.apk diff --git a/packages/CtsShim/apk/arm/CtsShimPriv.apk b/packages/CtsShim/apk/arm/CtsShimPriv.apk Binary files differindex 9dc2352e7d51..7fbeb3da05a3 100644 --- a/packages/CtsShim/apk/arm/CtsShimPriv.apk +++ b/packages/CtsShim/apk/arm/CtsShimPriv.apk diff --git a/packages/CtsShim/apk/x86/CtsShim.apk b/packages/CtsShim/apk/x86/CtsShim.apk Binary files differindex 7f5c94891473..e153c910d10a 100644 --- a/packages/CtsShim/apk/x86/CtsShim.apk +++ b/packages/CtsShim/apk/x86/CtsShim.apk diff --git a/packages/CtsShim/apk/x86/CtsShimPriv.apk b/packages/CtsShim/apk/x86/CtsShimPriv.apk Binary files differindex 388e939c097c..f0eaf02e0be5 100644 --- a/packages/CtsShim/apk/x86/CtsShimPriv.apk +++ b/packages/CtsShim/apk/x86/CtsShimPriv.apk diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java index a95677d0202f..5675c9986ac9 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.PackageInfo; 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 @@ public class PackageInstallerActivity extends AlertActivity { 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 0e89f56d2376..d3a9f8fe1196 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.annotation.Nullable; 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 @@ public class PackageUtil { /** * 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 e5f7613ab52b..06b1c1635644 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.NotificationManager; 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 com.android.packageinstaller.R; 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 @@ public class WearPackageInstallerService extends Service { 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 @@ public class WearPackageInstallerService extends Service { // 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 @@ public class WearPackageInstallerService extends Service { // 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 @@ public class WearPackageInstallerService extends Service { } } - 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 @@ public class WearPackageInstallerService extends Service { // 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 fdf9d0d2e050..c16949ace286 100644 --- a/packages/SettingsLib/res/values-af/strings.xml +++ b/packages/SettingsLib/res/values-af/strings.xml @@ -284,8 +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> - <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) --> - <skip /> + <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> diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml index f448a7e85975..4c6c7b85bfda 100644 --- a/packages/SettingsLib/res/values-am/strings.xml +++ b/packages/SettingsLib/res/values-am/strings.xml @@ -284,8 +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> - <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) --> - <skip /> + <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> diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml index b6e62498a69e..ef3649096887 100644 --- a/packages/SettingsLib/res/values-as/strings.xml +++ b/packages/SettingsLib/res/values-as/strings.xml @@ -284,8 +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> - <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) --> - <skip /> + <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> diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml index 8e95942fe83d..62bb24846abe 100644 --- a/packages/SettingsLib/res/values-az/strings.xml +++ b/packages/SettingsLib/res/values-az/strings.xml @@ -284,8 +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> - <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) --> - <skip /> + <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> diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml index 32f9ba0c1da5..40432f816a30 100644 --- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml +++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml @@ -284,8 +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> - <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) --> - <skip /> + <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> diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml index 95476edc091d..19ad5346cb53 100644 --- a/packages/SettingsLib/res/values-bg/strings.xml +++ b/packages/SettingsLib/res/values-bg/strings.xml @@ -284,8 +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> - <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) --> - <skip /> + <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> diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml index 2f486aa51158..4ef8871b3404 100644 --- a/packages/SettingsLib/res/values-bs/strings.xml +++ b/packages/SettingsLib/res/values-bs/strings.xml @@ -284,8 +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> - <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) --> - <skip /> + <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> diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml index ed3d8c550958..9ab80da4a379 100644 --- a/packages/SettingsLib/res/values-da/strings.xml +++ b/packages/SettingsLib/res/values-da/strings.xml @@ -284,8 +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> - <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) --> - <skip /> + <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> diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml index bce0e3d62559..73a6245a07c7 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> diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml index bdf65cc8f0cb..ceabc74922e6 100644 --- a/packages/SettingsLib/res/values-el/strings.xml +++ b/packages/SettingsLib/res/values-el/strings.xml @@ -284,8 +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> - <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) --> - <skip /> + <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> diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml index c013a734e255..fca1c507cd2a 100644 --- a/packages/SettingsLib/res/values-en-rAU/strings.xml +++ b/packages/SettingsLib/res/values-en-rAU/strings.xml @@ -284,8 +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> - <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) --> - <skip /> + <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> diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml index c013a734e255..fca1c507cd2a 100644 --- a/packages/SettingsLib/res/values-en-rCA/strings.xml +++ b/packages/SettingsLib/res/values-en-rCA/strings.xml @@ -284,8 +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> - <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) --> - <skip /> + <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> diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml index c013a734e255..fca1c507cd2a 100644 --- a/packages/SettingsLib/res/values-en-rGB/strings.xml +++ b/packages/SettingsLib/res/values-en-rGB/strings.xml @@ -284,8 +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> - <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) --> - <skip /> + <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> diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml index c013a734e255..fca1c507cd2a 100644 --- a/packages/SettingsLib/res/values-en-rIN/strings.xml +++ b/packages/SettingsLib/res/values-en-rIN/strings.xml @@ -284,8 +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> - <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) --> - <skip /> + <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> diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml index 303f2e5f1403..e2d488c137ce 100644 --- a/packages/SettingsLib/res/values-es-rUS/strings.xml +++ b/packages/SettingsLib/res/values-es-rUS/strings.xml @@ -284,8 +284,7 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Mostrar opciones de certificación de pantalla inalámbrica"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Aumentar nivel de registro Wi-Fi; mostrar por SSID RSSI en el selector de Wi-Fi"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Reduce el consumo de batería y mejora el rendimiento de la red"</string> - <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) --> - <skip /> + <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">"Con uso medido"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"Sin tarifa plana"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"Tamaños de búfer de Logger"</string> diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml index c7c374fd2c3e..e7d53f659c6e 100644 --- a/packages/SettingsLib/res/values-es/strings.xml +++ b/packages/SettingsLib/res/values-es/strings.xml @@ -284,8 +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> - <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) --> - <skip /> + <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> diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml index d5b96c13dfa4..f6d2c01db42e 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,8 +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> - <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) --> - <skip /> + <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> diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml index 12a6486ac65d..a893c755ae11 100644 --- a/packages/SettingsLib/res/values-fa/strings.xml +++ b/packages/SettingsLib/res/values-fa/strings.xml @@ -284,8 +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> - <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) --> - <skip /> + <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> diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml index c8cf2d131333..5fae2103130b 100644 --- a/packages/SettingsLib/res/values-fi/strings.xml +++ b/packages/SettingsLib/res/values-fi/strings.xml @@ -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> diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml index 397db9f3a1c9..689f26750c44 100644 --- a/packages/SettingsLib/res/values-fr-rCA/strings.xml +++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml @@ -284,8 +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> - <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) --> - <skip /> + <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> diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml index 1591141f41c3..c1d5548e1f07 100644 --- a/packages/SettingsLib/res/values-gl/strings.xml +++ b/packages/SettingsLib/res/values-gl/strings.xml @@ -284,8 +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> - <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) --> - <skip /> + <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> diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml index 167db2fd33e2..64cd891feee6 100644 --- a/packages/SettingsLib/res/values-hr/strings.xml +++ b/packages/SettingsLib/res/values-hr/strings.xml @@ -284,8 +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> - <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) --> - <skip /> + <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> diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml index 3c0072e3c0fc..22c01ace9d3f 100644 --- a/packages/SettingsLib/res/values-hy/strings.xml +++ b/packages/SettingsLib/res/values-hy/strings.xml @@ -284,8 +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> - <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) --> - <skip /> + <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> diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml index 9226c95a25fe..a578d311c74c 100644 --- a/packages/SettingsLib/res/values-in/strings.xml +++ b/packages/SettingsLib/res/values-in/strings.xml @@ -284,8 +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> - <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) --> - <skip /> + <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> diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml index 39dfcf8d8ebc..862dabda2960 100644 --- a/packages/SettingsLib/res/values-is/strings.xml +++ b/packages/SettingsLib/res/values-is/strings.xml @@ -284,8 +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> - <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) --> - <skip /> + <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> diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml index 957eb6a90c66..ff3df16617ca 100644 --- a/packages/SettingsLib/res/values-it/strings.xml +++ b/packages/SettingsLib/res/values-it/strings.xml @@ -284,8 +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> - <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) --> - <skip /> + <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> diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml index 994334f7c38c..754d4a05fdcc 100644 --- a/packages/SettingsLib/res/values-ka/strings.xml +++ b/packages/SettingsLib/res/values-ka/strings.xml @@ -284,8 +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> - <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) --> - <skip /> + <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> diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml index f8437b5bc5c8..50ff04d320f4 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> @@ -301,11 +301,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> @@ -318,10 +318,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> diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml index e42a7cf01718..f495857a307e 100644 --- a/packages/SettingsLib/res/values-kn/strings.xml +++ b/packages/SettingsLib/res/values-kn/strings.xml @@ -284,8 +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> - <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) --> - <skip /> + <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> diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml index 8443d1818f9b..782791ae1233 100644 --- a/packages/SettingsLib/res/values-ko/strings.xml +++ b/packages/SettingsLib/res/values-ko/strings.xml @@ -284,8 +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> - <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) --> - <skip /> + <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> diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml index 0702737f4392..3d9311090503 100644 --- a/packages/SettingsLib/res/values-ky/strings.xml +++ b/packages/SettingsLib/res/values-ky/strings.xml @@ -284,8 +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> - <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) --> - <skip /> + <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> diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml index 9ef0c25c0c6a..856f26c76320 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,8 +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> - <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) --> - <skip /> + <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> @@ -301,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> diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml index 860cd1dad72b..758fba7f5271 100644 --- a/packages/SettingsLib/res/values-lv/strings.xml +++ b/packages/SettingsLib/res/values-lv/strings.xml @@ -284,8 +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> - <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) --> - <skip /> + <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> diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml index d13afe04caf4..a662cd3c2d0a 100644 --- a/packages/SettingsLib/res/values-mk/strings.xml +++ b/packages/SettingsLib/res/values-mk/strings.xml @@ -284,8 +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> - <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) --> - <skip /> + <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> diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml index dfdbab3056e1..05e13936cd92 100644 --- a/packages/SettingsLib/res/values-mn/strings.xml +++ b/packages/SettingsLib/res/values-mn/strings.xml @@ -284,8 +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> - <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) --> - <skip /> + <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> diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml index de5abb6d5297..e5f676414ffc 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> diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml index c093c5082c2a..037436ec3f58 100644 --- a/packages/SettingsLib/res/values-my/strings.xml +++ b/packages/SettingsLib/res/values-my/strings.xml @@ -284,8 +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> - <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) --> - <skip /> + <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> diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml index 59b58c99710e..1ab840c10709 100644 --- a/packages/SettingsLib/res/values-nb/strings.xml +++ b/packages/SettingsLib/res/values-nb/strings.xml @@ -284,8 +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> - <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) --> - <skip /> + <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> diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml index eb5239e924b0..417cd95bcf16 100644 --- a/packages/SettingsLib/res/values-nl/strings.xml +++ b/packages/SettingsLib/res/values-nl/strings.xml @@ -284,8 +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> - <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) --> - <skip /> + <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> diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml index 13329fd399e5..74c14779b77b 100644 --- a/packages/SettingsLib/res/values-or/strings.xml +++ b/packages/SettingsLib/res/values-or/strings.xml @@ -496,7 +496,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> diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml index 9828db79e54f..68cc06109906 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,8 +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> - <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) --> - <skip /> + <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> diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml index 48dbbf856fed..9db0f5e9b2ea 100644 --- a/packages/SettingsLib/res/values-pl/strings.xml +++ b/packages/SettingsLib/res/values-pl/strings.xml @@ -284,8 +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> - <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) --> - <skip /> + <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> diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml index 3133738ab3c6..b33b2b510384 100644 --- a/packages/SettingsLib/res/values-pt-rBR/strings.xml +++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml @@ -284,8 +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> - <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) --> - <skip /> + <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> diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml index e1be6b829077..36b84681ae44 100644 --- a/packages/SettingsLib/res/values-pt-rPT/strings.xml +++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml @@ -284,8 +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> - <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) --> - <skip /> + <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> @@ -400,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> diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml index 3133738ab3c6..b33b2b510384 100644 --- a/packages/SettingsLib/res/values-pt/strings.xml +++ b/packages/SettingsLib/res/values-pt/strings.xml @@ -284,8 +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> - <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) --> - <skip /> + <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> diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml index 2abc4eab1a49..e784873c3f43 100644 --- a/packages/SettingsLib/res/values-ro/strings.xml +++ b/packages/SettingsLib/res/values-ro/strings.xml @@ -284,8 +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> - <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) --> - <skip /> + <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> diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml index d0c73aecfe21..bdda5ee5b0ee 100644 --- a/packages/SettingsLib/res/values-ru/strings.xml +++ b/packages/SettingsLib/res/values-ru/strings.xml @@ -284,8 +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> - <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) --> - <skip /> + <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> diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml index b9b602913ec0..ba710e29e1b1 100644 --- a/packages/SettingsLib/res/values-si/strings.xml +++ b/packages/SettingsLib/res/values-si/strings.xml @@ -284,8 +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> - <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) --> - <skip /> + <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> diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml index df0f1010a5f2..5abba6ff9405 100644 --- a/packages/SettingsLib/res/values-sk/strings.xml +++ b/packages/SettingsLib/res/values-sk/strings.xml @@ -284,8 +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> - <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) --> - <skip /> + <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> diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml index 0cdc19d33a11..15df19c81e0f 100644 --- a/packages/SettingsLib/res/values-sr/strings.xml +++ b/packages/SettingsLib/res/values-sr/strings.xml @@ -284,8 +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> - <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) --> - <skip /> + <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> diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml index 15b9577c7020..6b1a63c5b819 100644 --- a/packages/SettingsLib/res/values-sv/strings.xml +++ b/packages/SettingsLib/res/values-sv/strings.xml @@ -284,8 +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> - <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) --> - <skip /> + <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> diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml index 21d4f49f7a01..e041bea1867a 100644 --- a/packages/SettingsLib/res/values-sw/strings.xml +++ b/packages/SettingsLib/res/values-sw/strings.xml @@ -284,8 +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> - <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) --> - <skip /> + <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> diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml index 01a1ac3a4618..6c714207cd28 100644 --- a/packages/SettingsLib/res/values-tr/strings.xml +++ b/packages/SettingsLib/res/values-tr/strings.xml @@ -284,8 +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> - <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) --> - <skip /> + <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> diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml index dcf219febdeb..174f6fa1409f 100644 --- a/packages/SettingsLib/res/values-uk/strings.xml +++ b/packages/SettingsLib/res/values-uk/strings.xml @@ -284,8 +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> - <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) --> - <skip /> + <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> diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml index 7f0b00760d43..80f415748727 100644 --- a/packages/SettingsLib/res/values-uz/strings.xml +++ b/packages/SettingsLib/res/values-uz/strings.xml @@ -284,8 +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> - <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) --> - <skip /> + <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Bu rejim yoqilganda qurilmaning MAC manzili tasodifiy MAC manzillar yaratish imkoniyatli 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> diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml index dfd83b145c5e..33969938ad42 100644 --- a/packages/SettingsLib/res/values-zh-rHK/strings.xml +++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml @@ -284,8 +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> - <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) --> - <skip /> + <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> diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml index 61b38123d040..dfebe81383f1 100644 --- a/packages/SettingsLib/res/values-zh-rTW/strings.xml +++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml @@ -284,8 +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> - <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) --> - <skip /> + <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> diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml index f0fead78882d..45cd737c8c73 100644 --- a/packages/SettingsLib/res/values-zu/strings.xml +++ b/packages/SettingsLib/res/values-zu/strings.xml @@ -284,8 +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> - <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) --> - <skip /> + <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> diff --git a/packages/SettingsLib/res/values/arrays.xml b/packages/SettingsLib/res/values/arrays.xml index 7b58937049d1..d59d698efba2 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 7ca0e809143a..934f61091bcc 100644 --- a/packages/SettingsLib/res/values/strings.xml +++ b/packages/SettingsLib/res/values/strings.xml @@ -1365,4 +1365,12 @@ <!-- 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> </resources> diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java b/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java index c4ff71940d20..ae3194df28fe 100644 --- a/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java @@ -140,4 +140,15 @@ public class AppUtils { .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; + } + } } diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java index 436f2fa87394..1d06df08bd3a 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 @@ public class InfoMediaManager extends MediaManager { 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 @@ public class InfoMediaManager extends MediaManager { 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 @@ public class InfoMediaManager extends MediaManager { 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 @@ public class InfoMediaManager extends MediaManager { 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 @@ public class InfoMediaManager extends MediaManager { 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)); } @@ -434,7 +430,7 @@ public class InfoMediaManager extends MediaManager { } @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 4a7a60fde635..887a49b95279 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java @@ -27,10 +27,13 @@ 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; @@ -430,7 +433,8 @@ public class LocalMediaManager implements BluetoothCallback { 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) { @@ -454,6 +458,15 @@ public class LocalMediaManager implements BluetoothCallback { 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)) { @@ -476,10 +489,7 @@ public class LocalMediaManager implements BluetoothCallback { 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 f1c0f6b44150..139a12c44e0f 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_HEADPHONES; 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 abstract class MediaDevice implements Comparable<MediaDevice> { */ public void requestSetVolume(int volume) { - mRouterManager.requestSetVolume(mRouteInfo, volume); + mRouterManager.setRouteVolume(mRouteInfo, volume); } /** @@ -215,30 +211,6 @@ public abstract class MediaDevice implements Comparable<MediaDevice> { * * @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 42f2542e5c30..8ea5ff1bf662 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 @@ public class PhoneMediaDevice extends MediaDevice { 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 @@ public class PhoneMediaDevice extends MediaDevice { @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 2ed9c7b94d89..99c568a4707b 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 @@ public class InfoMediaManagerTest { } @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 @@ public class InfoMediaManagerTest { 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 @@ public class InfoMediaManagerTest { } @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); } 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 77316e91bae2..365a16c50b99 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 @@ -41,6 +41,7 @@ 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; @@ -560,6 +561,10 @@ public class LocalMediaManagerTest { 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); @@ -571,6 +576,7 @@ public class LocalMediaManagerTest { 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); @@ -634,6 +640,10 @@ public class LocalMediaManagerTest { 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); @@ -662,6 +672,7 @@ public class LocalMediaManagerTest { 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); 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 6664870a6257..47d4beb752c5 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 static org.mockito.Mockito.when; 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.Mock; 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 @@ public class MediaDeviceTest { 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 @@ public class MediaDeviceTest { 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 @@ public class MediaDeviceTest { 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 6f265dd603e5..47f6fe3bce02 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_USB_DEVICE; 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 @@ public class PhoneMediaDeviceTest { 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 d023d98f2b73..028c3041a50d 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 @@ public class SettingsHelper { @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 a5dce6da348f..3d7559b2c1a6 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 @@ class SettingsProtoDumpUtil { 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/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java index be0a8640760f..4a9eba2202e3 100644 --- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java +++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java @@ -587,7 +587,8 @@ public class SettingsBackupTest { 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 7fac7407bf6d..8086fd2c61d3 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 9695e418ce7f..2957dab231e2 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 d4bb3c6dc1f5..dd4100cafada 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 5c5ba816e5d7..dd8ed228c189 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 82c02a19a863..60e58fec45bc 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 7e7b763c459b..2376ffd2b2cf 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 05ff41274cd5..7cc2e6bfefba 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 bed7367cbaec..bb0496a481ec 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/SystemUI/Android.bp b/packages/SystemUI/Android.bp index b55d246de65c..7a27676237a1 100644 --- a/packages/SystemUI/Android.bp +++ b/packages/SystemUI/Android.bp @@ -129,6 +129,8 @@ android_library { "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 c483d0ec31e1..61b1e30845b3 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -719,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/statusbar/StatusBarStateController.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java index 6c4cbdf27fa5..d881cb6347fe 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 @@ public interface StatusBarStateController { boolean isDozing(); /** + * Is device pulsing. + */ + boolean isPulsing(); + + /** * Adds a state listener */ void addCallback(StateListener listener); diff --git a/packages/SystemUI/res/drawable/qs_media_background.xml b/packages/SystemUI/res/drawable/qs_media_background.xml index 2821e4c28bab..e79c9a40918c 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/layout/bubble_overflow_view.xml b/packages/SystemUI/res/layout/bubble_overflow_view.xml index 88a05ec5824a..1ed1f07fb277 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_dialog.xml b/packages/SystemUI/res/layout/controls_dialog.xml index 3effaf5fac5b..5ce9916b0489 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/keyguard_media_header.xml b/packages/SystemUI/res/layout/keyguard_media_header.xml index de9ef218083b..20ec10ca1e1b 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 66c0c5c275ed..416ee8147e33 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/qqs_media_panel.xml b/packages/SystemUI/res/layout/qqs_media_panel.xml index 403b5dc3a427..2e86732f3cad 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 a194569dcca4..d633ff40df9e 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 867676799b31..b27d096c12b5 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/system_icons.xml b/packages/SystemUI/res/layout/system_icons.xml index 6fb5590df6ed..818d1d77177b 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-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml index 9431f77d6754..6957e20d01b3 100644 --- a/packages/SystemUI/res/values-as/strings.xml +++ b/packages/SystemUI/res/values-as/strings.xml @@ -255,8 +255,7 @@ <!-- 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_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> @@ -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-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml index cad90dfa4481..a74917776d09 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> @@ -415,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> @@ -530,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> @@ -549,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> @@ -568,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> @@ -652,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> @@ -662,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-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml index cf8bae379fb0..599bf631ebe5 100644 --- a/packages/SystemUI/res/values-bn/strings.xml +++ b/packages/SystemUI/res/values-bn/strings.xml @@ -715,7 +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> - <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> diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml index 8dbd5aee6f88..8bce8ece357c 100644 --- a/packages/SystemUI/res/values-cs/strings.xml +++ b/packages/SystemUI/res/values-cs/strings.xml @@ -720,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> diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml index 0cf1b5347701..1f78537ca63d 100644 --- a/packages/SystemUI/res/values-de/strings.xml +++ b/packages/SystemUI/res/values-de/strings.xml @@ -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-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml index 8b5868f7a3a7..afbe13bf894c 100644 --- a/packages/SystemUI/res/values-gu/strings.xml +++ b/packages/SystemUI/res/values-gu/strings.xml @@ -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-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml index e6a9aa76a86d..1ce80ff71e6e 100644 --- a/packages/SystemUI/res/values-hy/strings.xml +++ b/packages/SystemUI/res/values-hy/strings.xml @@ -714,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> diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml index 738bc0a4a0eb..8f506952ed70 100644 --- a/packages/SystemUI/res/values-in/strings.xml +++ b/packages/SystemUI/res/values-in/strings.xml @@ -435,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> diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml index c127bd49fdea..fc139319a3b6 100644 --- a/packages/SystemUI/res/values-km/strings.xml +++ b/packages/SystemUI/res/values-km/strings.xml @@ -714,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> diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml index b514c993b5a2..fda3a051ded2 100644 --- a/packages/SystemUI/res/values-ky/strings.xml +++ b/packages/SystemUI/res/values-ky/strings.xml @@ -714,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> diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml index 1f1a6efd18bc..1ff99d586a47 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> diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml index fbe1b9e4cc09..8581a658dae9 100644 --- a/packages/SystemUI/res/values-ml/strings.xml +++ b/packages/SystemUI/res/values-ml/strings.xml @@ -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-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml index 5cd309cfaa23..482d60894cc5 100644 --- a/packages/SystemUI/res/values-ms/strings.xml +++ b/packages/SystemUI/res/values-ms/strings.xml @@ -965,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> diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml index 3568efb206f7..f5e7f120213d 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> @@ -676,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> @@ -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-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml index 0e508fc76c8c..087ab50ebc66 100644 --- a/packages/SystemUI/res/values-pl/strings.xml +++ b/packages/SystemUI/res/values-pl/strings.xml @@ -720,7 +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> - <string name="no_shortcut" msgid="7176375126961212514">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> nie obsługuje ustawień dotyczących rozmowy"</string> + <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> diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml index 7441982ffe3c..cea04db2b9d9 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> @@ -432,8 +432,8 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Iniciar"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Parar"</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 aplicação"</string> - <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Arraste para a direita para mudar rapidamente de aplicação."</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> @@ -719,20 +719,20 @@ <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> @@ -887,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> @@ -909,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> @@ -929,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> @@ -946,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> @@ -957,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> @@ -967,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> @@ -985,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> diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml index 8debda0ee9d0..6fd6d8742879 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> diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml index 9c96b405f85c..aade5c238128 100644 --- a/packages/SystemUI/res/values-sl/strings.xml +++ b/packages/SystemUI/res/values-sl/strings.xml @@ -439,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> diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml index cc1398be94e6..0d85f21d4fbc 100644 --- a/packages/SystemUI/res/values-sq/strings.xml +++ b/packages/SystemUI/res/values-sq/strings.xml @@ -255,8 +255,7 @@ <!-- no translation found for accessibility_work_mode (1280025758672376313) --> <skip /> <string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Njoftimi është hequr."</string> - <!-- no translation found for accessibility_bubble_dismissed (270358867566720729) --> - <skip /> + <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> @@ -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 58cfcb8d5478..7fd03715dd7f 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> @@ -415,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> @@ -530,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> @@ -549,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> @@ -568,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> @@ -652,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> @@ -662,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-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml index db8e2f71fce7..6129f2a0a4b9 100644 --- a/packages/SystemUI/res/values-ur/strings.xml +++ b/packages/SystemUI/res/values-ur/strings.xml @@ -255,8 +255,7 @@ <!-- 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_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> @@ -715,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> @@ -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-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml index 26cbcf2da9cb..f54728001b85 100644 --- a/packages/SystemUI/res/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res/values-zh-rCN/strings.xml @@ -414,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> diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml index d3256ef34bd7..c4195940d11a 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/config.xml b/packages/SystemUI/res/values/config.xml index 62335abd4329..14075743ce34 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 c68c814532fe..7d3988d6f99f 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -1168,7 +1168,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 --> @@ -1310,7 +1310,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/strings.xml b/packages/SystemUI/res/values/strings.xml index 2b3e661c4f7e..023c77d5db14 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -1253,6 +1253,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 +2611,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] --> @@ -2710,9 +2717,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 6e25625d3b88..f0edd6388ae7 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" /> @@ -768,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 592f6c2a0dff..68f4b746caa2 100644 --- a/packages/SystemUI/shared/Android.bp +++ b/packages/SystemUI/shared/Android.bp @@ -38,9 +38,7 @@ android_library { "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 43b9c7574141..aaadea6ec38f 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 26ef1d68858e..0350f2d47569 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 @@ oneway interface IOverviewProxy { 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 @@ oneway interface IOverviewProxy { 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 @@ oneway interface IOverviewProxy { /** * 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 c2a4af93b917..acc691304ca5 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.SurfaceControl; import android.view.View; import android.view.ViewRootImpl; +/** + * TODO: Remove this class + */ public class SurfaceControlCompat { final SurfaceControl mSurfaceControl; @@ -37,4 +40,8 @@ public class SurfaceControlCompat { 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 2e6b195d6a16..31fe22e57084 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; 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 @@ public class SyncRtSurfaceTransactionApplierCompat { 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 class SyncRtSurfaceTransactionApplierCompat { 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 class SyncRtSurfaceTransactionApplierCompat { public static class SurfaceParams { public static class Builder { - final SurfaceControlCompat surface; + final SurfaceControl surface; int flags; float alpha; float cornerRadius; @@ -224,6 +199,13 @@ public class SyncRtSurfaceTransactionApplierCompat { * @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 class SyncRtSurfaceTransactionApplierCompat { */ 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 @@ public class SyncRtSurfaceTransactionApplierCompat { } 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 class SyncRtSurfaceTransactionApplierCompat { 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 c1c91f7e5079..bdb6c063521f 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 @@ package com.android.systemui.shared.system; 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 @@ public class TransactionCompat { 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 000000000000..dd613263e5c2 --- /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/systemui/CameraAvailabilityListener.kt b/packages/SystemUI/src/com/android/systemui/CameraAvailabilityListener.kt index 284074e76ae2..3015710e8a98 100644 --- a/packages/SystemUI/src/com/android/systemui/CameraAvailabilityListener.kt +++ b/packages/SystemUI/src/com/android/systemui/CameraAvailabilityListener.kt @@ -37,20 +37,22 @@ class CameraAvailabilityListener( 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 @@ class CameraAvailabilityListener( computed.top.roundToInt(), computed.right.roundToInt(), computed.bottom.roundToInt()) + excludedPackageIds = excludedPackages.split(",").toSet() } /** @@ -87,6 +90,10 @@ class CameraAvailabilityListener( listeners.remove(callback) } + private fun isExcluded(packageId: String): Boolean { + return excludedPackageIds.contains(packageId) + } + private fun registerCameraListener() { cameraManager.registerAvailabilityCallback(executor, availabilityCallback) } @@ -118,9 +125,10 @@ class CameraAvailabilityListener( 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 @@ class CameraAvailabilityListener( return p } } -}
\ No newline at end of file +} diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java index 73dfd32d03a2..b7275634c6a6 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 class SystemActions extends SystemUI { 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 @@ public class SystemActions extends SystemUI { 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 @@ public class SystemActions extends SystemUI { 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 @@ public class SystemActions extends SystemUI { 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 @@ public class SystemActions extends SystemUI { 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 @@ public class SystemActions extends SystemUI { "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 @@ public class SystemActions extends SystemUI { 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 @@ public class SystemActions extends SystemUI { 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 @@ public class SystemActions extends SystemUI { handleAccessibilityButtonChooser(); break; } + case INTENT_ACTION_ACCESSIBILITY_SHORTCUT: { + handleAccessibilityShortcut(); + break; + } default: break; } diff --git a/packages/SystemUI/src/com/android/systemui/broadcast/UserBroadcastDispatcher.kt b/packages/SystemUI/src/com/android/systemui/broadcast/UserBroadcastDispatcher.kt index 4e84f06f51a7..3272fb7545e2 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.internal.util.Preconditions 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 @@ class UserBroadcastDispatcher( */ 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 cafa0604d88e..ad8d57bbf23f 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java @@ -153,6 +153,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi private final NotificationGroupManager mNotificationGroupManager; private final ShadeController mShadeController; private final FloatingContentCoordinator mFloatingContentCoordinator; + private final BubbleDataRepository mDataRepository; private BubbleData mBubbleData; private ScrimView mBubbleScrim; @@ -294,13 +295,14 @@ public class BubbleController implements ConfigurationController.ConfigurationLi 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); } /** @@ -322,6 +324,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi FeatureFlags featureFlags, DumpManager dumpManager, FloatingContentCoordinator floatingContentCoordinator, + BubbleDataRepository dataRepository, SysUiState sysUiState, INotificationManager notificationManager) { dumpManager.registerDumpable(TAG, this); @@ -331,6 +334,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi mNotifUserManager = notifUserManager; mZenModeController = zenModeController; mFloatingContentCoordinator = floatingContentCoordinator; + mDataRepository = dataRepository; mINotificationManager = notificationManager; mZenModeController.addCallback(new ZenModeController.Callback() { @Override @@ -1018,6 +1022,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi // 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; @@ -1027,6 +1032,9 @@ public class BubbleController implements ConfigurationController.ConfigurationLi 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() @@ -1056,9 +1064,12 @@ public class BubbleController implements ConfigurationController.ConfigurationLi } } } + mDataRepository.removeBubbles(mCurrentUserId, bubblesToBeRemovedFromRepository); if (update.addedBubble != null) { + mDataRepository.addBubble(mCurrentUserId, update.addedBubble); mStackView.addBubble(update.addedBubble); + } if (update.updatedBubble != null) { @@ -1068,6 +1079,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi // 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); } 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 000000000000..b9825e1d21e5 --- /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 b3c2c6d60708..baf92dc7abe7 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java @@ -57,6 +57,7 @@ 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; @@ -456,6 +457,19 @@ public class BubbleExpandedView extends LinearLayout { 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) { diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.java index 13669a68defa..e96bef36ba18 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 @@ public class BubbleOverflow implements BubbleViewProvider { 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 de54c353fc85..c2ca9fad6d43 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_BUBBLES; 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.util.Log; 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 @@ public class BubbleOverflowActivity extends Activity { - 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 @@ public class BubbleOverflowActivity extends Activity { } 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 @@ class BubbleOverflowAdapter extends RecyclerView.Adapter<BubbleOverflowAdapter.V 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 c802b59faba9..341458763625 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java @@ -465,6 +465,7 @@ public class BubbleStackView extends FrameLayout mBubbleData.setExpanded(!mBubbleData.isExpanded()); } } + mExpandedAnimationController.onGestureFinished(); } }; @@ -1075,26 +1076,27 @@ public class BubbleStackView extends FrameLayout @Override public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) { super.onInitializeAccessibilityNodeInfoInternal(info); + setupLocalMenu(info); + } + + void setupLocalMenu(AccessibilityNodeInfo info) { + Resources res = mContext.getResources(); - // Custom actions. + // 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. 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 72d646e0554d..e3b630b049f5 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 android.content.Context; 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 @@ public interface BubbleModule { FeatureFlags featureFlags, DumpManager dumpManager, FloatingContentCoordinator floatingContentCoordinator, + BubbleDataRepository bubbleDataRepository, SysUiState sysUiState, INotificationManager notifManager) { return new BubbleController( @@ -84,6 +86,7 @@ public interface BubbleModule { 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 000000000000..149e2c4c4022 --- /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 000000000000..e1f675b83583 --- /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 000000000000..d0f76077cd51 --- /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 000000000000..1e91653c6db7 --- /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/ControlsFavoritePersistenceWrapper.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsFavoritePersistenceWrapper.kt index cde258a056db..1bda841d4a63 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 com.android.systemui.backup.BackupHelper 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 @@ class ControlsFavoritePersistenceWrapper( 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/ControlsListingControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt index 3590f1f4fad8..48f191d12801 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt @@ -66,6 +66,8 @@ class ControlsListingControllerImpl @VisibleForTesting constructor( ) private var serviceListing = serviceListingBuilder(context) + // All operations in background thread + private val callbacks = mutableSetOf<ControlsListingController.ControlsListingCallback>() companion object { private const val TAG = "ControlsListingControllerImpl" @@ -116,9 +118,6 @@ class ControlsListingControllerImpl @VisibleForTesting constructor( } } - // All operations in background thread - private val callbacks = mutableSetOf<ControlsListingController.ControlsListingCallback>() - /** * Adds a callback to this controller. * 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 5c30b5a5bf45..0d23557ffa9e 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 @@ class ControlsRequestReceiver : BroadcastReceiver() { 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/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java index 10776c91df84..e1081cd5ef82 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 android.util.Log; 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 @@ import java.util.function.Consumer; 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 @@ public class DozeSensors { 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 @@ public class DozeSensors { 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/media/IlluminationDrawable.kt b/packages/SystemUI/src/com/android/systemui/media/IlluminationDrawable.kt new file mode 100644 index 000000000000..937472735bb0 --- /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/pip/PipBoundsHandler.java b/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java index 9d9e74abc38f..3eeadc367b0d 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 android.window.WindowContainerTransaction; 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 8d797f139b43..8d6ce4718aef 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.Map; 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 @@ import java.util.function.Consumer; * 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(); @@ -192,6 +196,7 @@ public class PipTaskOrganizer extends TaskOrganizer { mSurfaceControlTransactionFactory; private PictureInPictureParams mPictureInPictureParams; + @Inject public PipTaskOrganizer(Context context, @NonNull PipBoundsHandler boundsHandler, @NonNull PipSurfaceTransactionHelper surfaceTransactionHelper, @Nullable Divider divider) { 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 a86a884c8016..0841bb70f205 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 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio DeviceConfigProxy deviceConfig, PipBoundsHandler pipBoundsHandler, PipSnapAlgorithm pipSnapAlgorithm, + PipTaskOrganizer pipTaskOrganizer, PipSurfaceTransactionHelper surfaceTransactionHelper, Divider divider) { mContext = context; @@ -215,8 +216,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio 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/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java index fae8af4f575a..f49732d98ae8 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 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio @Inject public PipManager(Context context, BroadcastDispatcher broadcastDispatcher, PipBoundsHandler pipBoundsHandler, + PipTaskOrganizer pipTaskOrganizer, PipSurfaceTransactionHelper surfaceTransactionHelper, Divider divider) { if (mInitialized) { @@ -250,8 +251,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio 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/QSMediaPlayer.java b/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java index e76cd5116818..174441bdf065 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.app.PendingIntent; 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 android.widget.TextView; 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 @@ public class QSMediaPlayer extends MediaControlPanel { 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 @@ public class QSMediaPlayer extends MediaControlPanel { 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/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java index 8835e5db50c0..54a928d78a89 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java @@ -454,11 +454,8 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D 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 f77ff8cd7949..5cb75e60e22a 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.ImageButton; 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 @@ public class QuickQSMediaPlayer extends MediaControlPanel { 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/SecureSetting.java b/packages/SystemUI/src/com/android/systemui/qs/SecureSetting.java index c22463964a19..65d815053e47 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 abstract class SecureSetting extends ContentObserver implements Listenabl public int getCurrentUser() { return mUserId; } + + public String getKey() { + return mSettingName; + } + + public boolean isListening() { + return mListening; + } } diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java index 555202a2b02c..e67b3d715c84 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 @@ public class Divider extends SystemUI implements DividerView.DividerCallbacks, 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 @@ public class Divider extends SystemUI implements DividerView.DividerCallbacks, } } + 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/SplitScreenTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java index 717edc591d7f..2862c836942f 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 @@ class SplitScreenTaskOrganizer extends TaskOrganizer { + 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/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java index 229aa6d98e0a..2bef355d59f3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java @@ -178,6 +178,11 @@ public class StatusBarStateControllerImpl implements SysuiStatusBarStateControll } @Override + public boolean isPulsing() { + return mPulsing; + } + + @Override public float getDozeAmount() { return mDozeAmount; } 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 9738bcc69279..c78370ec4643 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.NotificationFilter 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 @@ open class NotificationRankingManager @Inject constructor( .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 1c1b2bb087f0..a0f9dc91ce68 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 @@ import javax.inject.Singleton @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/init/NotificationsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt index c9754048e1d1..6e4fcd5f97b1 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.NotificationActivityStarter 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 @@ class NotificationsControllerImpl @Inject constructor( 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 @@ class NotificationsControllerImpl @Inject constructor( } 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/row/BindStage.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/BindStage.java index 29447caa1240..cc917dda2a80 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 @@ package com.android.systemui.statusbar.notification.row; import android.annotation.MainThread; import android.util.ArrayMap; +import android.util.Log; import androidx.annotation.NonNull; @@ -66,8 +67,10 @@ public abstract class BindStage<Params> extends BindRequester { 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 @@ public abstract class BindStage<Params> extends BindRequester { */ 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/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java index 2e5af9a7414a..f7ad50edb2f6 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 @@ -2366,6 +2366,11 @@ public class ExpandableNotificationRow extends ActivatableNotificationView 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 f8d9c4648ac9..7a6109d2ce78 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 @@ public class ExpandableNotificationRowController { 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/NotifBindPipeline.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifBindPipeline.java index e4e3ebcf7671..3ee267362bc0 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 @@ public final class NotifBindPipeline { 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 @@ public final class NotifBindPipeline { 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/stack/NotificationSectionsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java index d02037cf61fd..6eec1ca33e14 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 @@ public class NotificationSectionsManager implements StackScrollAlgorithm.Section @Nullable private View.OnClickListener mOnClearGentleNotifsClickListener; private SectionHeaderView mAlertingHeader; + private SectionHeaderView mIncomingHeader; private PeopleHubView mPeopleHubView; private boolean mPeopleHubVisible = false; @@ -199,6 +200,11 @@ public class NotificationSectionsManager implements StackScrollAlgorithm.Section 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 @@ public class NotificationSectionsManager implements StackScrollAlgorithm.Section || view == mMediaControlsView || view == mPeopleHubView || view == mAlertingHeader + || view == mIncomingHeader || !Objects.equals(getBucket(view), getBucket(previous)); } @@ -229,6 +236,8 @@ public class NotificationSectionsManager implements StackScrollAlgorithm.Section 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 @@ public class NotificationSectionsManager implements StackScrollAlgorithm.Section // 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 @@ public class NotificationSectionsManager implements StackScrollAlgorithm.Section 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 @@ public class NotificationSectionsManager implements StackScrollAlgorithm.Section // 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 @@ public class NotificationSectionsManager implements StackScrollAlgorithm.Section 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 7093dd8b39e3..7f32c004808a 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.graphics.Rect; 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 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd 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 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd 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 0680c7f70b97..79515415f1c3 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.DataSaverController.Listener; 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 @@ public class AutoTileManager { 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 @@ public class AutoTileManager { 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 @@ public class AutoTileManager { 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 @@ public class AutoTileManager { 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 @@ public class AutoTileManager { } }; - private SecureSetting mColorsSetting; - private final DataSaverController.Listener mDataSaverListener = new Listener() { @Override public void onDataSaverChanged(boolean isDataSaving) { @@ -213,4 +240,47 @@ public class AutoTileManager { } } }; + + @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 9bf14e43da03..4afeba8de211 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 @@ public final class DozeServiceHost implements DozeHost { dozing = false; } - mStatusBarStateController.setIsDozing(dozing); } @@ -260,7 +259,6 @@ public final class DozeServiceHost implements DozeHost { 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/LightBarTransitionsController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java index 092dd49ba617..5b7ffd2d4164 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 class LightBarTransitionsController implements Dumpable, Callbacks, 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 a2e7306d4931..8a5c8b0898bc 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 @@ public class LockscreenLockIconController { 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 @@ public class LockscreenLockIconController { } @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 @@ public class LockscreenLockIconController { /** * Propagate {@link StatusBar} pulsing state. */ - public void setPulsing(boolean pulsing) { - mPulsing = pulsing; + private void setPulsing(boolean pulsing) { update(); } @@ -461,7 +463,8 @@ public class LockscreenLockIconController { 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 @@ public class LockscreenLockIconController { 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 @@ public class LockscreenLockIconController { } private void setDozing(boolean isDozing) { - mDozing = isDozing; update(); } @@ -504,7 +507,8 @@ public class LockscreenLockIconController { * @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/NotificationShadeWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowController.java index fc6a02840891..567ddb680848 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowController.java @@ -321,7 +321,8 @@ public class NotificationShadeWindowController implements Callback, Dumpable, || state.mPanelVisible || state.mKeyguardFadingAway || state.mBouncerShowing || state.mHeadsUpShowing || state.mScrimsVisibility != ScrimController.TRANSPARENT) - || state.mBackgroundBlurRadius > 0; + || state.mBackgroundBlurRadius > 0 + || state.mLaunchingActivity; } private void applyFitsSystemWindows(State state) { @@ -485,6 +486,11 @@ public class NotificationShadeWindowController implements Callback, Dumpable, apply(mCurrentState); } + void setLaunchingActivity(boolean launching) { + mCurrentState.mLaunchingActivity = launching; + apply(mCurrentState); + } + public void setScrimsVisibility(int scrimsVisibility) { mCurrentState.mScrimsVisibility = scrimsVisibility; apply(mCurrentState); @@ -645,6 +651,7 @@ public class NotificationShadeWindowController implements Callback, Dumpable, boolean mForceCollapsed; boolean mForceDozeBrightness; boolean mForceUserActivity; + boolean mLaunchingActivity; boolean mBackdropShowing; boolean mWallpaperSupportsAmbientMode; boolean mNotTouchable; 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 596a607bb8ad..0d2589847bcb 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 @@ public class NotificationShadeWindowViewController { 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 class NotificationShadeWindowViewController { 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 class NotificationShadeWindowViewController { } } - 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 977a307a3d95..7c41bcd09b57 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 @@ public class PhoneStatusBarView extends PanelBar { @Override protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); + updateResources(); // May trigger cutout space layout-ing if (updateOrientationAndCutout()) { @@ -298,6 +299,24 @@ public class PhoneStatusBarView extends PanelBar { 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/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index bbf83bc2057a..dd54a3d800fb 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 @@ public class StatusBar extends SystemUI implements DemoMode, 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 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 d40b5f9728dd..1df617d68374 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java @@ -483,7 +483,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit 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( diff --git a/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java b/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java index c22b718fa50f..c7e9accce093 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.AnimatorListenerAdapter; 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 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged 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 64cac84ff24e..93f45c51f0eb 100644 --- a/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java +++ b/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java @@ -189,8 +189,8 @@ public class SystemWindows { 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; } 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 58906d7bd2d3..e2f303e87d87 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java @@ -140,6 +140,8 @@ public class BubbleControllerTest extends SysuiTestCase { private KeyguardBypassController mKeyguardBypassController; @Mock private FloatingContentCoordinator mFloatingContentCoordinator; + @Mock + private BubbleDataRepository mDataRepository; private SysUiState mSysUiState; private boolean mSysUiStateBubblesExpanded; @@ -275,6 +277,7 @@ public class BubbleControllerTest extends SysuiTestCase { mFeatureFlagsOldPipeline, mDumpManager, mFloatingContentCoordinator, + mDataRepository, mSysUiState, mock(INotificationManager.class)); mBubbleController.setExpandListener(mBubbleExpandListener); 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 ec1a797533fa..8a83b84c6b5e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java @@ -135,6 +135,8 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase { @Mock private FloatingContentCoordinator mFloatingContentCoordinator; @Mock + private BubbleDataRepository mDataRepository; + @Mock private NotificationShadeWindowView mNotificationShadeWindowView; private SysUiState mSysUiState = new SysUiState(); @@ -250,6 +252,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase { mFeatureFlagsNewPipeline, mDumpManager, mFloatingContentCoordinator, + mDataRepository, mSysUiState, mock(INotificationManager.class)); mBubbleController.addNotifCallback(mNotifCallback); 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 7815ae78823a..1542b8675ede 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 @@ public class TestableBubbleController extends BubbleController { 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/controls/management/ControlsListingControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt index 13a77083255c..9b40c5e87b79 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.Mock 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 @@ class ControlsListingControllerImplTest : SysuiTestCase() { } @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/qs/QSPanelTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java index 9d35e53e7421..128d6e5612f1 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.never; 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; @@ -37,6 +39,7 @@ 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; @@ -46,6 +49,7 @@ import com.android.systemui.qs.customize.QSCustomizer; 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; @@ -100,8 +104,14 @@ public class QSPanelTest extends SysuiTestCase { @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); 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 966fa88653bf..11477395a781 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java @@ -122,11 +122,6 @@ public class QSTileHostTest extends SysuiTestCase { 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()); } @@ -210,34 +205,6 @@ public class QSTileHostTest extends SysuiTestCase { } @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"); 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 72a65034922c..53ef86660867 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.assertFalse; 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.content.pm.ServiceInfo; 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.R; 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.junit.runner.RunWith; 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 @@ import java.util.Set; @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 @@ public class TileQueryHelperTest extends SysuiTestCase { private QSTileHost mQSTileHost; @Mock private PackageManager mPackageManager; - @Mock - private QSLogger mQSLogger; @Captor private ArgumentCaptor<List<TileQueryHelper.TileInfo>> mCaptor; @@ -112,8 +109,8 @@ public class TileQueryHelperTest extends SysuiTestCase { @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 @@ public class TileQueryHelperTest extends SysuiTestCase { } @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 @@ public class TileQueryHelperTest extends SysuiTestCase { 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/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java index 1cb4d898f9d2..c4bd1b281b24 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.verify; 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 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { 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 67ad37b2d29a..1a6921a1d136 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.doReturn; 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 @@ import java.util.List; @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 @@ public class AutoTileManagerTest extends SysuiTestCase { @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 @@ public class AutoTileManagerTest extends SysuiTestCase { 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/NotificationShadeWindowViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java index cc2d1c25de38..e04d25b17c71 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 @@ public class NotificationShadeWindowViewTest extends SysuiTestCase { @Mock private NotificationStackScrollLayout mNotificationStackScrollLayout; @Mock private NotificationShadeDepthController mNotificationShadeDepthController; @Mock private SuperStatusBarViewFactory mStatusBarViewFactory; + @Mock private NotificationShadeWindowController mNotificationShadeWindowController; @Before public void setUp() { @@ -121,7 +122,7 @@ public class NotificationShadeWindowViewTest extends SysuiTestCase { mNotificationPanelViewController, mStatusBarViewFactory); mController.setupExpandedStatusBar(); - mController.setService(mStatusBar); + mController.setService(mStatusBar, mNotificationShadeWindowController); mController.setDragDownHelper(mDragDownHelper); } diff --git a/packages/Tethering/common/TetheringLib/Android.bp b/packages/Tethering/common/TetheringLib/Android.bp index 8ae1593949f1..d029d2bded79 100644 --- a/packages/Tethering/common/TetheringLib/Android.bp +++ b/packages/Tethering/common/TetheringLib/Android.bp @@ -94,6 +94,15 @@ droidstubs { "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 { @@ -102,6 +111,15 @@ droidstubs { "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 { @@ -110,6 +128,15 @@ droidstubs { "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 { diff --git a/packages/Tethering/res/values/config.xml b/packages/Tethering/res/values/config.xml index 83c99d22fda7..9dda7166a293 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 16ae8ade19da..4c78a74d5358 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/OffloadController.java b/packages/Tethering/src/com/android/networkstack/tethering/OffloadController.java index 1817f35f1dcd..88c77b07e7e3 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.NetworkStats.UID_TETHERING; 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 @@ public class OffloadController { 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 @@ public class OffloadController { 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 @@ public class OffloadController { 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 0a95a5e0073b..b2a43c47d1c6 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 android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; 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 @@ public class Tethering { 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<>(); diff --git a/packages/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java b/packages/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java index aeac437e24e3..9d4e74732729 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 class TetheringConfiguration { 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 class TetheringConfiguration { 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 @@ public class TetheringConfiguration { 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 @@ public class TetheringConfiguration { 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 @@ public class TetheringConfiguration { 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 @@ public class TetheringConfiguration { 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 9b54b5ff2403..802f2acb3310 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 @@ public abstract class TetheringDependencies { } /** + * 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, 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 088a663190b8..b291438937c7 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 android.provider.Settings.Global.TETHER_OFFLOAD_DISABLED; 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.LinkProperties; 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.filters.SmallTest; 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 @@ public class OffloadControllerTest { @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 @@ public class OffloadControllerTest { 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 @@ public class OffloadControllerTest { 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 @@ public class OffloadControllerTest { tetherStatsProviderCaptor.capture()); mTetherStatsProvider = tetherStatsProviderCaptor.getValue(); assertNotNull(mTetherStatsProvider); + mTetherStatsProviderCb = new TestableNetworkStatsProviderCbBinder(); mTetherStatsProvider.setProviderCallbackBinder(mTetherStatsProviderCb); return offload; } @@ -352,9 +361,9 @@ public class OffloadControllerTest { 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 @@ public class OffloadControllerTest { .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 @@ public class OffloadControllerTest { .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 @@ public class OffloadControllerTest { 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 @@ public class OffloadControllerTest { OffloadHardwareInterface.ControlCallback callback = mControlCallbackCaptor.getValue(); callback.onStoppedLimitReached(); - verify(mTetherStatsProviderCb, times(1)).notifyStatsUpdated(anyInt(), any(), any()); + mTetherStatsProviderCb.expectNotifyStatsUpdated(); } @Test @@ -695,8 +693,8 @@ public class OffloadControllerTest { 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 @@ public class OffloadControllerTest { // 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 @@ public class OffloadControllerTest { 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 07ddea43f4e8..e8ba5b8168d7 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 @@ public class TetheringConfigurationTest { 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 @@ public class TetheringConfigurationTest { } @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 0363f5f9989f..fff7a70f54d0 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.ArgumentCaptor; 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 @@ public class TetheringTest { 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 @@ public class TetheringTest { } } - 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 @@ public class TetheringTest { } @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 @@ public class TetheringTest { } @Override + public EntitlementManager getEntitlementManager(Context ctx, StateMachine target, + SharedLog log, int what) { + mEntitleMgr = spy(super.getEntitlementManager(ctx, target, log, what)); + return mEntitleMgr; + } + + @Override public boolean isTetheringSupported() { return true; } @@ -359,7 +381,8 @@ public class TetheringTest { @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,17 @@ public class TetheringTest { 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); + mTethering.dump(mockFd, mockPw, new String[0]); + verify(mConfig).dump(any()); + verify(mEntitleMgr).dump(any()); + verify(mOffloadCtrl).dump(any()); + } + // TODO: Test that a request for hotspot mode doesn't interfere with an // already operating tethering mode interface. } diff --git a/services/Android.bp b/services/Android.bp index 6d637bedeef7..882085a7d0ba 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 @@ java_library { "services.usb", "services.voiceinteraction", "services.wifi", + "service-blobstore", + "service-jobscheduler", "android.hidl.base-V1.0-java", ], @@ -83,7 +92,6 @@ java_library { // Uncomment to enable output of certain warnings (deprecated, unchecked) //javacflags: ["-Xlint"], - } // native library @@ -128,13 +136,13 @@ droidstubs { 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 284a2f2626a4..21a0c7489827 100644 --- a/services/accessibility/Android.bp +++ b/services/accessibility/Android.bp @@ -7,6 +7,7 @@ filegroup { java_library_static { name: "services.accessibility", + defaults: ["services_defaults"], srcs: [":services.accessibility-sources"], libs: ["services.core"], } diff --git a/services/appprediction/Android.bp b/services/appprediction/Android.bp index e14e1df0b5c7..c12f62fc6cd1 100644 --- a/services/appprediction/Android.bp +++ b/services/appprediction/Android.bp @@ -7,6 +7,7 @@ filegroup { 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 0b3899d15993..fdc5f810db22 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 @@ public class AppPredictionPerUserService extends 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 @@ public class AppPredictionPerUserService extends @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 class AppPredictionPerUserService extends 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 @@ public class AppPredictionPerUserService extends @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 class AppPredictionPerUserService extends 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 class AppPredictionPerUserService extends 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 @@ public class AppPredictionPerUserService extends */ @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 @@ public class AppPredictionPerUserService extends @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 @@ public class AppPredictionPerUserService extends @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 @@ public class AppPredictionPerUserService extends } 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 ceb1cafcebeb..a57ff11fa20f 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 @@ public class RemoteAppPredictionService extends } /** + * 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 54cf6cec78ea..83a9aa493bb0 100644 --- a/services/appwidget/Android.bp +++ b/services/appwidget/Android.bp @@ -7,6 +7,7 @@ filegroup { 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 539eb1a5220e..1e65e8459edf 100644 --- a/services/autofill/Android.bp +++ b/services/autofill/Android.bp @@ -7,6 +7,7 @@ filegroup { 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/AutofillInlineSuggestionsRequestSession.java b/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java index ce11c76e5c6a..22451e1d992e 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java +++ b/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java @@ -37,6 +37,7 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.view.IInlineSuggestionsRequestCallback; import com.android.internal.view.IInlineSuggestionsResponseCallback; import com.android.internal.view.InlineSuggestionsRequestInfo; +import com.android.server.autofill.ui.InlineSuggestionFactory; import com.android.server.inputmethod.InputMethodManagerInternal; import java.lang.ref.WeakReference; @@ -242,7 +243,8 @@ final class AutofillInlineSuggestionsRequestSession { } if (sDebug) Log.d(TAG, "Send inline response: " + response.getInlineSuggestions().size()); try { - mResponseCallback.onInlineSuggestionsResponse(mAutofillId, response); + mResponseCallback.onInlineSuggestionsResponse(mAutofillId, + InlineSuggestionFactory.copy(response)); } catch (RemoteException e) { Slog.e(TAG, "RemoteException sending InlineSuggestionsResponse to IME"); } diff --git a/services/autofill/java/com/android/server/autofill/RemoteInlineSuggestionRenderService.java b/services/autofill/java/com/android/server/autofill/RemoteInlineSuggestionRenderService.java index 255adcd92da3..617c111c6c38 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 @@ public final class RemoteInlineSuggestionRenderService extends 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/ui/InlineContentProviderImpl.java b/services/autofill/java/com/android/server/autofill/ui/InlineContentProviderImpl.java new file mode 100644 index 000000000000..819f2b813a5e --- /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. + */ +public 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/InlineSuggestionFactory.java b/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java index 79c9efa48d73..e74463a8584b 100644 --- a/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java +++ b/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java @@ -24,14 +24,11 @@ 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.Slog; -import android.view.SurfaceControlViewHost; import android.view.autofill.AutofillId; import android.view.autofill.AutofillManager; import android.view.autofill.AutofillValue; @@ -41,12 +38,8 @@ 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; @@ -73,6 +66,27 @@ public final class InlineSuggestionFactory { } /** + * Returns a copy of the response, 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. + */ + @NonNull + public static InlineSuggestionsResponse copy(@NonNull InlineSuggestionsResponse response) { + final ArrayList<InlineSuggestion> copiedInlineSuggestions = new ArrayList<>(); + for (InlineSuggestion inlineSuggestion : response.getInlineSuggestions()) { + final IInlineContentProvider contentProvider = inlineSuggestion.getContentProvider(); + if (contentProvider instanceof InlineContentProviderImpl) { + copiedInlineSuggestions.add(new + InlineSuggestion(inlineSuggestion.getInfo(), + ((InlineContentProviderImpl) contentProvider).copy())); + } else { + copiedInlineSuggestions.add(inlineSuggestion); + } + } + return new InlineSuggestionsResponse(copiedInlineSuggestions); + } + + /** * Creates an {@link InlineSuggestionsResponse} with the {@code datasets} provided by the * autofill service, potentially filtering the datasets. */ @@ -276,78 +290,20 @@ public final class InlineSuggestionFactory { 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 000000000000..00a5283c9b1f --- /dev/null +++ b/services/autofill/java/com/android/server/autofill/ui/RemoteInlineSuggestionUi.java @@ -0,0 +1,291 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.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.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 the same single + * thread handler to be processed. + * + * TODO(b/154683107): implement the reference counting in case there are multiple active + * SurfacePackages at the same time. This will not happen for now since all the InlineSuggestions + * sharing the same UI will be sent to the same IME window, so the previous view will be detached + * before the new view are attached to the window. + */ +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 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(this::handleSurfacePackageReleased); + } + + /** + * 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 handleSurfacePackageReleased() { + cancelPendingReleaseViewRequest(); + + // Schedule a delayed release view request + mDelayedReleaseViewRunnable = () -> { + if (mInlineSuggestionUi != null) { + try { + 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 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) + throws RemoteException { + if (sDebug) Slog.d(TAG, "Sending new SurfacePackage to IME"); + mInlineContentCallback.onContent(result, mActualWidth, mActualHeight); + } + }); + } catch (RemoteException e) { + Slog.w(TAG, "RemoteException calling getSurfacePackage."); + } + } + } + + 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; + mWaitingForUiCreation = false; + mActualWidth = width; + mActualHeight = height; + if (mInlineContentCallback != null) { + try { + 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 000000000000..9d23c171800d --- /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 f02da2076706..56b788e34d35 100644 --- a/services/backup/Android.bp +++ b/services/backup/Android.bp @@ -7,6 +7,7 @@ filegroup { 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 9677a7d83bfb..e25104227b71 100644 --- a/services/companion/Android.bp +++ b/services/companion/Android.bp @@ -7,6 +7,7 @@ filegroup { 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 96e20726fed3..7006430067ec 100644 --- a/services/contentcapture/Android.bp +++ b/services/contentcapture/Android.bp @@ -7,6 +7,7 @@ filegroup { 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 d17f06f79e97..3fe3cd252592 100644 --- a/services/contentsuggestions/Android.bp +++ b/services/contentsuggestions/Android.bp @@ -7,6 +7,7 @@ filegroup { 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 181ce8958992..21ac3cd24089 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -148,6 +148,7 @@ java_genrule { java_library { name: "services.core", + defaults: ["services_defaults"], static_libs: ["services.core.priorityboosted"], } diff --git a/services/core/java/com/android/server/ServiceWatcher.java b/services/core/java/com/android/server/ServiceWatcher.java index cfb79aa3a210..b1b5ec01df6a 100644 --- a/services/core/java/com/android/server/ServiceWatcher.java +++ b/services/core/java/com/android/server/ServiceWatcher.java @@ -169,7 +169,11 @@ public class ServiceWatcher implements ServiceConnection { @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 14fe0c5e3c22..be539456ae7c 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -1579,6 +1579,14 @@ class StorageManagerService extends IStorageManager.Stub 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 @@ class StorageManagerService extends IStorageManager.Stub } } + 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 70b639846e1e..26cb208a3d47 100644 --- a/services/core/java/com/android/server/UiModeManagerService.java +++ b/services/core/java/com/android/server/UiModeManagerService.java @@ -450,6 +450,14 @@ final class UiModeManagerService extends SystemService { 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; @@ -1385,8 +1393,11 @@ final class UiModeManagerService extends SystemService { 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 @@ -1399,6 +1410,8 @@ final class UiModeManagerService extends SystemService { switch (cmd) { case "night": return handleNightMode(); + case "time": + return handleCustomTime(); default: return handleDefaultCommands(cmd); } @@ -1409,6 +1422,34 @@ final class UiModeManagerService extends SystemService { 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(); @@ -1424,7 +1465,8 @@ final class UiModeManagerService extends SystemService { 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 419389f7abef..cca604655f3d 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 @@ public final class ActiveServices { 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 @@ public final class ActiveServices { 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 @@ public final class ActiveServices { 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 6b917bc2249d..4ff421e6cdf5 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 @@ final class ActivityManagerConstants extends ContentObserver { 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 @@ final class ActivityManagerConstants extends ContentObserver { case KEY_FORCE_BACKGROUND_CHECK_ON_RESTRICTED_APPS: updateForceRestrictedBackgroundCheck(); break; + case KEY_MIN_ASSOC_LOG_DURATION: + updateMinAssocLogDuration(); + break; default: break; } @@ -659,6 +671,12 @@ final class ActivityManagerConstants extends ContentObserver { 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 @@ final class ActivityManagerConstants extends ContentObserver { 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 8d3515202126..d914bda3eff4 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 @@ public class ActivityManagerService extends IActivityManager.Stub } @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); } @@ -20201,4 +20180,15 @@ public class ActivityManagerService extends IActivityManager.Stub 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/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java index 86d9028f53dc..f9d204fa008e 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.os.Trace; 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 @@ public final class CachedAppOptimizer { /** * 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 @@ public final class CachedAppOptimizer { */ @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/ProcessStatsService.java b/services/core/java/com/android/server/am/ProcessStatsService.java index 6d4a9f42ccd9..a0349493edbc 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 @@ public final class ProcessStatsService extends IProcessStats.Stub { 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/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index d76ee685ca4d..63e01e034d7e 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.IAppOpsAsyncNotedCallback; 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 @@ public class AppOpsService extends IAppOpsService.Stub { 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 @@ public class AppOpsService extends IAppOpsService.Stub { } } + 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; @@ -3031,13 +3077,12 @@ public class AppOpsService extends IAppOpsService.Stub { 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 @@ public class AppOpsService extends IAppOpsService.Stub { } 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 @@ public class AppOpsService extends IAppOpsService.Stub { + 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 @@ public class AppOpsService extends IAppOpsService.Stub { // 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 @@ public class AppOpsService extends IAppOpsService.Stub { } @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 @@ public class AppOpsService extends IAppOpsService.Stub { 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 @@ public class AppOpsService extends IAppOpsService.Stub { 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 @@ public class AppOpsService extends IAppOpsService.Stub { + 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 @@ public class AppOpsService extends IAppOpsService.Stub { + 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 @@ public class AppOpsService extends IAppOpsService.Stub { } } + 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 @@ public class AppOpsService extends IAppOpsService.Stub { 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 604b9f1ead6d..9cd903940a83 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 7cac376ea7ae..17baead84f9d 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 @@ public class AudioService extends IAudioService.Stub */ @NonNull public List<AudioProductStrategy> getAudioProductStrategies() { + // verify permissions + enforceModifyAudioRoutingPermission(); return AudioProductStrategy.getAudioProductStrategies(); } @@ -1226,6 +1228,8 @@ public class AudioService extends IAudioService.Stub */ @NonNull public List<AudioVolumeGroup> getAudioVolumeGroups() { + // verify permissions + enforceModifyAudioRoutingPermission(); return AudioVolumeGroup.getAudioVolumeGroups(); } diff --git a/services/core/java/com/android/server/connectivity/DataConnectionStats.java b/services/core/java/com/android/server/connectivity/DataConnectionStats.java index 5010e46a74eb..3e619200d414 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 @@ public class DataConnectionStats extends BroadcastReceiver { 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 @@ public class DataConnectionStats extends BroadcastReceiver { 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 @@ public class DataConnectionStats extends BroadcastReceiver { @Override public void onServiceStateChanged(ServiceState state) { mServiceState = state; + mNrState = state.getNrState(); notePhoneDataConnectionState(); } diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index bafeb77c55e6..9411c5629457 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 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call 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 24e1b4edc8a6..4b6430d5197c 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 @@ final class DisplayPowerState { /** * 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/integrity/AppIntegrityManagerServiceImpl.java b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java index 2cae1d64ca34..905a10bd641b 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 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub { // 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 4f8708a7599a..b2bf1fce0d07 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.CancellationSignal; 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 @@ public class LocationManagerService extends ILocationManager.Stub { } @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; 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 000000000000..909873f07993 --- /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 93d45c882e1c..ac982dd86d85 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 class LockSettingsService extends ILockSettings.Stub { 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 */); } diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java index a5de90c93aab..a435f1e16b80 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 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider return; } - sessionInfo = new RoutingSessionInfo.Builder(sessionInfo) - .setProviderId(getUniqueId()) - .build(); + sessionInfo = updateSessionInfo(sessionInfo); boolean duplicateSessionAlreadyExists = false; synchronized (mLock) { @@ -348,9 +346,7 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider return; } - sessionInfo = new RoutingSessionInfo.Builder(sessionInfo) - .setProviderId(getUniqueId()) - .build(); + sessionInfo = updateSessionInfo(sessionInfo); boolean found = false; synchronized (mLock) { @@ -380,9 +376,7 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider return; } - sessionInfo = new RoutingSessionInfo.Builder(sessionInfo) - .setProviderId(getUniqueId()) - .build(); + sessionInfo = updateSessionInfo(sessionInfo); boolean found = false; synchronized (mLock) { @@ -403,6 +397,13 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider 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 ec941c8aea59..3283fd9b2c51 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 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { writePolicyAL(); } - enableFirewallChainUL(FIREWALL_CHAIN_STANDBY, true); setRestrictBackgroundUL(mLoadedRestrictBackground, "init_service"); updateRulesForGlobalChangeAL(false); updateNotificationsNL(); @@ -871,6 +870,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { 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 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } /** + * 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 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { 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 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { * * @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 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } 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/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java index 8bb7c0f530e4..a604625460a7 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 @@ abstract public class ManagedServices { 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 @@ abstract public class ManagedServices { 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 @@ abstract public class ManagedServices { } } } - 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) { diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 5470b9c8c041..bc7bd2355195 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -943,7 +943,8 @@ public class NotificationManagerService extends SystemService { .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); @@ -8611,15 +8612,19 @@ public class NotificationManagerService extends SystemService { 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/NotificationRecordLogger.java b/services/core/java/com/android/server/notification/NotificationRecordLogger.java index 34e6ec18be88..e06e01e53852 100644 --- a/services/core/java/com/android/server/notification/NotificationRecordLogger.java +++ b/services/core/java/com/android/server/notification/NotificationRecordLogger.java @@ -229,7 +229,7 @@ public interface NotificationRecordLogger { 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), @@ -245,7 +245,24 @@ public interface NotificationRecordLogger { 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) { @@ -264,6 +281,21 @@ public interface NotificationRecordLogger { } 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/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java index acce6992ea79..92c145275ac8 100644 --- a/services/core/java/com/android/server/pm/ApexManager.java +++ b/services/core/java/com/android/server/pm/ApexManager.java @@ -509,7 +509,7 @@ public abstract class ApexManager { ParsedPackage pp = parseResult.parsedPackage; try { pp.setSigningDetails( - ParsingPackageUtils.collectCertificates(pp, false)); + ParsingPackageUtils.getSigningDetails(pp, false)); } catch (PackageParserException e) { throw new IllegalStateException( "Unable to collect certificates for " + ai.modulePath, e); diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java index 118fdcbcb736..70d1adecc6f3 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 @@ public class AppsFilter { } 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 @@ public class AppsFilter { 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 @@ public class AppsFilter { 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 @@ public class AppsFilter { 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 @@ public class AppsFilter { } 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 @@ public class AppsFilter { 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 @@ public class AppsFilter { 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 @@ public class AppsFilter { 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 @@ public class AppsFilter { 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 @@ public class AppsFilter { 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 @@ public class AppsFilter { } } } finally { - Trace.endSection(); + Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index 3367cd556b2b..5b5f334803e5 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 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements 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 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements 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 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements 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 class PackageInstallerService extends IPackageInstaller.Stub implements 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 3df044fab30d..e0d057a8d7f3 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.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.ParseResult; +import android.content.pm.parsing.result.ParseTypeImpl; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Binder; @@ -188,6 +190,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { 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 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { 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 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { mPrepared = prepared; mCommitted = committed; + mDestroyed = destroyed; mStagedSessionReady = isReady; mStagedSessionFailed = isFailed; mStagedSessionApplied = isApplied; @@ -711,6 +715,13 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } } + /** {@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 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } /** + * 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") @@ -2016,15 +2040,16 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { // 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"); @@ -2113,16 +2138,22 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } } 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); @@ -2543,7 +2574,13 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { + 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 @@ -2553,11 +2590,12 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { 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(); } @@ -2917,6 +2955,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { /** {@hide} */ void setStagedSessionReady() { synchronized (mLock) { + if (mDestroyed) return; // Do not allow destroyed staged session to change state mStagedSessionReady = true; mStagedSessionApplied = false; mStagedSessionFailed = false; @@ -2930,6 +2969,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { 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; @@ -2944,6 +2984,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { /** {@hide} */ void setStagedSessionApplied() { synchronized (mLock) { + if (mDestroyed) return; // Do not allow destroyed staged session to change state mStagedSessionReady = false; mStagedSessionApplied = true; mStagedSessionFailed = false; @@ -3188,7 +3229,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { */ void write(@NonNull XmlSerializer out, @NonNull File sessionsDir) throws IOException { synchronized (mLock) { - if (mDestroyed) { + if (mDestroyed && !params.isStaged) { return; } @@ -3214,6 +3255,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } 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); @@ -3343,6 +3385,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { 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); @@ -3464,7 +3507,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { 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 f288f1fd9e79..f31dbbf077bb 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.VersionedPackage; 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.ParsedPermission; 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; @@ -2177,7 +2180,8 @@ public class PackageManagerService extends IPackageManager.Stub 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); @@ -4425,11 +4429,6 @@ public class PackageManagerService extends IPackageManager.Stub 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); @@ -5802,15 +5801,9 @@ public class PackageManagerService extends IPackageManager.Stub @Override public ChangedPackages getChangedPackages(int sequenceNumber, int userId) { - final int callingUid = Binder.getCallingUid(); - if (getInstantAppPackageName(callingUid) != null) { - return null; - } - if (!mUserManager.exists(userId)) { + if (getInstantAppPackageName(Binder.getCallingUid()) != null) { return null; } - mPermissionManager.enforceCrossUserPermission( - callingUid, userId, false, false, "getChangedPackages"); synchronized (mLock) { if (sequenceNumber >= mChangedPackagesSequenceNumber) { return null; @@ -8815,10 +8808,8 @@ public class PackageManagerService extends IPackageManager.Stub 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; @@ -9069,7 +9060,7 @@ public class PackageManagerService extends IPackageManager.Stub 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 { @@ -12725,13 +12716,14 @@ public class PackageManagerService extends IPackageManager.Stub } 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(); @@ -12742,7 +12734,8 @@ public class PackageManagerService extends IPackageManager.Stub @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; } @@ -12751,6 +12744,7 @@ public class PackageManagerService extends IPackageManager.Stub 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, @@ -12868,7 +12862,7 @@ public class PackageManagerService extends IPackageManager.Stub } } if (sendAdded) { - sendPackageAddedForUser(packageName, pkgSetting, userId); + sendPackageAddedForUser(packageName, pkgSetting, userId, DataLoaderType.NONE); return true; } if (sendRemoved) { @@ -13101,7 +13095,7 @@ public class PackageManagerService extends IPackageManager.Stub prepareAppDataAfterInstallLIF(pkgSetting.pkg); } } - sendPackageAddedForUser(packageName, pkgSetting, userId); + sendPackageAddedForUser(packageName, pkgSetting, userId, DataLoaderType.NONE); synchronized (mLock) { updateSequenceNumberLP(pkgSetting, new int[]{ userId }); } @@ -15250,12 +15244,21 @@ public class PackageManagerService extends IPackageManager.Stub && 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()); @@ -17064,7 +17067,7 @@ public class PackageManagerService extends IPackageManager.Stub 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); @@ -18406,7 +18409,8 @@ public class PackageManagerService extends IPackageManager.Stub 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); } } @@ -25390,7 +25394,8 @@ interface PackageSender { 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 88f442c7b6a0..bc94528c07f0 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.PackageManager.NameNotFoundException; 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.ArtManager; 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 @@ class PackageManagerShellCommand extends ShellCommand { long sessionSize = 0; + ParseTypeImpl input = ParseTypeImpl.forDefaultParsing(); for (String inPath : inPaths) { final ParcelFileDescriptor fd = openFileForSystem(inPath, "r"); if (fd == null) { @@ -512,12 +514,19 @@ class PackageManagerShellCommand extends ShellCommand { 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/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java index 9a297d601a6b..a83fa32ec9a9 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.text.TextUtils; 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 @@ public class StagingManager { 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 @@ public class StagingManager { 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 @@ public class StagingManager { + session.sessionId + " [" + errorMessage + "]"); session.setStagedSessionFailed( SessionInfo.STAGED_SESSION_VERIFICATION_FAILED, errorMessage); + mPreRebootVerificationHandler.onPreRebootVerificationComplete( + session.sessionId); return; } mPreRebootVerificationHandler.notifyPreRebootVerification_Apk_Complete( @@ -880,7 +886,8 @@ public class StagingManager { 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 @@ public class StagingManager { } } - 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; + } + 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; } - abortSession(session); - 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 @@ public class StagingManager { // 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 @@ public class StagingManager { } } + 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 @@ public class StagingManager { @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 @@ public class StagingManager { 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 @@ public class StagingManager { * 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 @@ public class StagingManager { } } catch (PackageManagerException e) { session.setStagedSessionFailed(e.error, e.getMessage()); + onPreRebootVerificationComplete(session.sessionId); return; } @@ -1301,6 +1396,7 @@ public class StagingManager { // TODO(b/118865310): abort the session on apexd. } catch (PackageManagerException e) { session.setStagedSessionFailed(e.error, e.getMessage()); + onPreRebootVerificationComplete(session.sessionId); } } @@ -1323,9 +1419,18 @@ public class StagingManager { 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 @@ public class StagingManager { // 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/parsing/PackageParser2.java b/services/core/java/com/android/server/pm/parsing/PackageParser2.java index e860c4857bf4..1145057452c2 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; 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.os.SystemClock; 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 @@ public class PackageParser2 implements AutoCloseable { * * 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/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java index 45ebbb6efc6d..a967f3d7c4f9 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 com.android.server.policy.SoftRestrictedPermissionPolicy; 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; @@ -417,6 +419,11 @@ public class PermissionManagerService extends IPermissionManager.Stub { 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 @@ public class PermissionManagerService extends IPermissionManager.Stub { } @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 @@ public class PermissionManagerService extends IPermissionManager.Stub { } @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 356d0abc1d19..57a25eddf7ce 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 @@ public abstract class PermissionManagerServiceInternal extends PermissionManager /** 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 92184e87a357..341fadc3b577 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.pm.permission.PermissionManagerServiceInternal; 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 @@ public final class PermissionPolicyService extends SystemService { @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 final class PermissionPolicyService extends SystemService { 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 @@ public final class PermissionPolicyService extends SystemService { packageManagerInternal.getPackageList(new PackageListObserver() { @Override public void onPackageAdded(String packageName, int uid) { - onPackageChanged(packageName, 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 @@ public final class PermissionPolicyService extends SystemService { 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 @@ public final class PermissionPolicyService extends SystemService { // 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 @@ public final class PermissionPolicyService extends SystemService { 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 @@ public final class PermissionPolicyService extends SystemService { 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/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java index 6726cc829c81..3336697ef359 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.PackageParser; 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 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { } // 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 4bc774413ac0..f4c77a0b88ca 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 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware @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 d6390184e3bd..49c781905898 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.RemoteException; 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 @@ class SoundTriggerModule implements IHwBinder.DeathRecipient { } @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(); + } + // Trigger the callbacks outside of the lock to avoid deadlocks. + for (ISoundTriggerCallback callback : callbacks) { + try { + callback.onModuleDied(); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } } - reset(); } /** @@ -379,15 +392,13 @@ class SoundTriggerModule implements IHwBinder.DeathRecipient { /** * 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 373cb8be9c66..3b4c4235d8a4 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.AppOpsManager.OP_FLAG_TRUSTED_PROXY; 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.abs; 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 @@ public class StatsPullAtomService extends SystemService { 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 @@ public class StatsPullAtomService extends SystemService { 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 @@ public class StatsPullAtomService extends SystemService { 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/textclassifier/TextClassificationManagerService.java b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java index 5657c74ce3ad..e675f4e8a46c 100644 --- a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java +++ b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java @@ -241,7 +241,7 @@ public final class TextClassificationManagerService extends ITextClassifierServi handleRequest( event.getSystemTextClassifierMetadata(), /* verifyCallingPackage= */ true, - /* attemptToBind= */ false, + /* attemptToBind= */ true, service -> service.onSelectionEvent(sessionId, event), "onSelectionEvent", NO_OP_CALLBACK); @@ -260,7 +260,7 @@ public final class TextClassificationManagerService extends ITextClassifierServi handleRequest( systemTcMetadata, /* verifyCallingPackage= */ true, - /* attemptToBind= */ false, + /* attemptToBind= */ true, service -> service.onTextClassifierEvent(sessionId, event), "onTextClassifierEvent", NO_OP_CALLBACK); diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java index 8f71943129fa..2314afc787c3 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.TvInputHardwareInfo; 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 @@ class TvInputHardwareManager implements TvInputHal.Callback { 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 @@ class TvInputHardwareManager implements TvInputHal.Callback { 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 @@ class TvInputHardwareManager implements TvInputHal.Callback { 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 @@ class TvInputHardwareManager implements TvInputHal.Callback { 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 @@ class TvInputHardwareManager implements TvInputHal.Callback { // *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 @@ class TvInputHardwareManager implements TvInputHal.Callback { mCallingUid = callingUid; mResolvedUserId = resolvedUserId; mOnFirstFrameCaptured = null; + mResourceClientProfile = profile; if (mHardware != null && mCallback != null) { try { @@ -698,10 +712,14 @@ class TvInputHardwareManager implements TvInputHal.Callback { 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 @@ class TvInputHardwareManager implements TvInputHal.Callback { + ", 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 2f70840cfc8b..41aa4ee65f30 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 @@ package com.android.server.tv.tunerresourcemanager; 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 com.android.server.SystemService; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; @@ -71,7 +74,8 @@ public class TunerResourceManagerService extends SystemService { @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 @@ public class TunerResourceManagerService extends SystemService { 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 @@ public class TunerResourceManagerService extends SystemService { @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 @@ public class TunerResourceManagerService extends SystemService { @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."); + } + synchronized (mLock) { + return isHigherPriorityInternal(challengerProfile, holderProfile); } - return true; } } @@ -381,7 +388,7 @@ public class TunerResourceManagerService extends SystemService { } 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 @@ public class TunerResourceManagerService extends SystemService { 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 @@ public class TunerResourceManagerService extends SystemService { } @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 @@ public class TunerResourceManagerService extends SystemService { @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 @@ public class TunerResourceManagerService extends SystemService { } 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 6734ce76675d..72cdf4afb007 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.FORCE_PERSISTABLE_URI_PERMISSIONS; 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 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub { 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 0dbc9155757e..f05217c0b47a 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; 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; @@ -1892,13 +1891,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A 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)) { diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java index 2413386db268..9df3f855ad86 100644 --- a/services/core/java/com/android/server/wm/ActivityStack.java +++ b/services/core/java/com/android/server/wm/ActivityStack.java @@ -242,12 +242,6 @@ class ActivityStack extends Task { */ 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. */ @@ -846,58 +840,6 @@ class ActivityStack extends Task { 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(); @@ -1010,16 +952,6 @@ class ActivityStack extends Task { } } - 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) { @@ -1389,7 +1321,7 @@ class ActivityStack extends Task { boolean preserveWindows, boolean notifyClients) { mTopActivityOccludesKeyguard = false; mTopDismissingKeyguardActivity = null; - mStackSupervisor.getKeyguardController().beginActivityVisibilityUpdate(); + mStackSupervisor.beginActivityVisibilityUpdate(); try { mEnsureActivitiesVisibleHelper.process( starting, configChanges, preserveWindows, notifyClients); @@ -1400,7 +1332,7 @@ class ActivityStack extends Task { notifyActivityDrawnLocked(null); } } finally { - mStackSupervisor.getKeyguardController().endActivityVisibilityUpdate(); + mStackSupervisor.endActivityVisibilityUpdate(); } } @@ -2697,10 +2629,6 @@ class ActivityStack extends Task { // 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 { @@ -2740,10 +2668,6 @@ class ActivityStack extends Task { * 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 */); diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java index 9026b81c4f2a..9a3ef4b1a637 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.Process.SYSTEM_UID; 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; @@ -332,11 +331,10 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { 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; @@ -784,6 +782,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { r.launchCount++; r.lastLaunchTime = SystemClock.uptimeMillis(); + proc.setLastActivityLaunchTime(r.lastLaunchTime); if (DEBUG_ALL) Slog.v(TAG, "Launching: " + r); @@ -915,6 +914,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { 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. @@ -1415,18 +1415,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { 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 = @@ -1924,6 +1913,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { 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) { @@ -2312,6 +2302,24 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { "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. */ @@ -2490,12 +2498,6 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { 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. @@ -2505,7 +2507,6 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { 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."); diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java index 654ccc80f8a8..67fe9685fd2a 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 @@ public class AppTransitionController { // 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/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 72e38386f1f9..1f10c467e1e6 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -2547,6 +2547,9 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } 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); } @@ -5241,25 +5244,13 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo * 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; } diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index 8aace212d094..53b536cf712f 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_LIGHT_STATUS_BARS; 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.InputDevice; 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 @@ public class DisplayPolicy { private boolean mDreamingLockscreen; private boolean mAllowLockscreenWhenOn; - private InputConsumer mInputConsumer = null; + @VisibleForTesting + InputConsumer mInputConsumer = null; private PointerLocationView mPointerLocationView; @@ -1372,13 +1375,6 @@ public class DisplayPolicy { 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 @@ public class DisplayPolicy { 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 @@ public class DisplayPolicy { 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 @@ public class DisplayPolicy { // 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 @@ public class DisplayPolicy { && (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 @@ public class DisplayPolicy { mLastNotificationShadeForcesShowingNavigation = notificationShadeForcesShowingNavigation; } - boolean isNavigationBarRequestedVisible() { - final InsetsSourceProvider provider = - mDisplayContent.getInsetsStateController().peekSourceProvider(ITYPE_NAVIGATION_BAR); - return provider == null - ? InsetsState.getDefaultVisibility(ITYPE_NAVIGATION_BAR) - : provider.isClientVisible(); - } - - void updateHideNavInputEventReceiver(boolean navVisible, boolean navAllowedHidden) { + 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 @@ public class DisplayPolicy { 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/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java index 5a9bf809fa4a..317bb43adb98 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.InsetsController.ANIMATION_TYPE_SHOW; 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 @@ class InsetsPolicy { || 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 @@ class InsetsPolicy { 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/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java index f672394251f2..4c10d5819c10 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 @@ class KeyguardController { 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 @@ class KeyguardController { } /** - * 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 @@ class KeyguardController { && !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 @@ class KeyguardController { 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 ccd51de28c88..d8a4ecbbc650 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 @@ class RecentTasks { 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 @@ class RecentTasks { } // Trim the set of tasks to the active set - trimInactiveRecentTasks(); + if (canTrimTask) { + trimInactiveRecentTasks(); + } notifyTaskPersisterLocked(task, false /* flush */); } diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index a691736e754a..9a30f1c8e11d 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 @@ class RootWindowContainer extends WindowContainer<DisplayContent> /** 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 @@ class RootWindowContainer extends WindowContainer<DisplayContent> */ 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 @@ class RootWindowContainer extends WindowContainer<DisplayContent> notifyClients); } } finally { - mStackSupervisor.getKeyguardController().endActivityVisibilityUpdate(); - mInEnsureActivitiesVisible = false; + mStackSupervisor.endActivityVisibilityUpdate(); } } @@ -2509,20 +2504,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent> 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); diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 8903609ddaed..44a8daaba1b1 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -3334,6 +3334,16 @@ class Task extends WindowContainer<WindowContainer> { }); } + 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); } @@ -4552,7 +4562,14 @@ class Task extends WindowContainer<WindowContainer> { 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/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java index 75295e6d248e..0a1ee2b79711 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 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { 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(); diff --git a/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java b/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java index 79baab6bfbb6..06c2b1687fa4 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 @@ public class TaskTapPointerEventListener implements PointerEventListener { 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 @@ public class TaskTapPointerEventListener implements PointerEventListener { 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 @@ public class TaskTapPointerEventListener implements PointerEventListener { 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/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 6789d3fa1f3a..73126c8b6b6a 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_QS_DIALOG; 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; @@ -926,8 +927,14 @@ public class WindowManagerService extends IWindowManager.Stub } 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; } } @@ -1367,6 +1374,7 @@ public class WindowManagerService extends IWindowManager.Stub case TYPE_NOTIFICATION_SHADE: case TYPE_NAVIGATION_BAR: case TYPE_INPUT_METHOD_DIALOG: + case TYPE_VOLUME_OVERLAY: return true; } return false; @@ -8051,7 +8059,7 @@ public class WindowManagerService extends IWindowManager.Stub | 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; diff --git a/services/coverage/Android.bp b/services/coverage/Android.bp index e4f54644df46..df054b006cd3 100644 --- a/services/coverage/Android.bp +++ b/services/coverage/Android.bp @@ -7,6 +7,7 @@ filegroup { 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 2f6592bd33b0..7a80fb1b8856 100644 --- a/services/devicepolicy/Android.bp +++ b/services/devicepolicy/Android.bp @@ -7,6 +7,7 @@ filegroup { java_library_static { name: "services.devicepolicy", + defaults: ["services_defaults"], srcs: [":services.devicepolicy-sources"], libs: [ diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp index 992a4ef76f04..c3c215730e4c 100644 --- a/services/incremental/IncrementalService.cpp +++ b/services/incremental/IncrementalService.cpp @@ -1670,9 +1670,15 @@ IncrementalService::DataLoaderStub::~DataLoaderStub() = default; void IncrementalService::DataLoaderStub::cleanupResources() { requestDestroy(); + + auto now = Clock::now(); + + std::unique_lock lock(mMutex); mParams = {}; mControl = {}; - waitForStatus(IDataLoaderStatusListener::DATA_LOADER_DESTROYED, std::chrono::seconds(60)); + mStatusCondition.wait_until(lock, now + 60s, [this] { + return mCurrentStatus == IDataLoaderStatusListener::DATA_LOADER_DESTROYED; + }); mListener = {}; mId = kInvalidStorageId; } @@ -1706,7 +1712,7 @@ bool IncrementalService::DataLoaderStub::requestDestroy() { bool IncrementalService::DataLoaderStub::setTargetStatus(int newStatus) { int oldStatus, curStatus; { - std::unique_lock lock(mStatusMutex); + std::unique_lock lock(mMutex); oldStatus = mTargetStatus; curStatus = mCurrentStatus; setTargetStatusLocked(newStatus); @@ -1721,13 +1727,6 @@ void IncrementalService::DataLoaderStub::setTargetStatusLocked(int 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; }); -} - bool IncrementalService::DataLoaderStub::bind() { bool result = false; auto status = mService.mDataLoaderManager->bindToDataLoader(mId, mParams, this, &result); @@ -1776,7 +1775,7 @@ bool IncrementalService::DataLoaderStub::fsmStep() { int currentStatus; int targetStatus; { - std::unique_lock lock(mStatusMutex); + std::unique_lock lock(mMutex); currentStatus = mCurrentStatus; targetStatus = mTargetStatus; } @@ -1828,8 +1827,9 @@ binder::Status IncrementalService::DataLoaderStub::onStatusChanged(MountId mount } int targetStatus, oldStatus; + DataLoaderStatusListener listener; { - std::unique_lock lock(mStatusMutex); + std::unique_lock lock(mMutex); if (mCurrentStatus == newStatus) { return binder::Status::ok(); } @@ -1838,6 +1838,8 @@ binder::Status IncrementalService::DataLoaderStub::onStatusChanged(MountId mount mCurrentStatus = newStatus; targetStatus = mTargetStatus; + listener = mListener; + if (mCurrentStatus == IDataLoaderStatusListener::DATA_LOADER_UNAVAILABLE) { // For unavailable, reset target status. setTargetStatusLocked(IDataLoaderStatusListener::DATA_LOADER_UNAVAILABLE); @@ -1847,8 +1849,8 @@ binder::Status IncrementalService::DataLoaderStub::onStatusChanged(MountId mount 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(); diff --git a/services/incremental/IncrementalService.h b/services/incremental/IncrementalService.h index d5c612daee58..cf310b15b6d9 100644 --- a/services/incremental/IncrementalService.h +++ b/services/incremental/IncrementalService.h @@ -188,17 +188,17 @@ private: 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; 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; diff --git a/services/midi/Android.bp b/services/midi/Android.bp index 20e00834d0ad..6bce5b51ecb7 100644 --- a/services/midi/Android.bp +++ b/services/midi/Android.bp @@ -7,6 +7,7 @@ filegroup { 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 8b444b0fed41..afea1a073cab 100644 --- a/services/net/Android.bp +++ b/services/net/Android.bp @@ -7,6 +7,7 @@ filegroup { java_library_static { name: "services.net", + defaults: ["services_defaults"], srcs: [ ":net-module-utils-srcs", ":services.net-sources", diff --git a/services/people/Android.bp b/services/people/Android.bp index d64097a03ae9..c863f1f5919f 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/DataManager.java b/services/people/java/com/android/server/people/data/DataManager.java index d9ca4152026e..107c41a47507 100644 --- a/services/people/java/com/android/server/people/data/DataManager.java +++ b/services/people/java/com/android/server/people/data/DataManager.java @@ -229,6 +229,10 @@ public class DataManager { 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()); } 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 d09d0b379769..43acd459f84b 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.app.prediction.AppTargetId; 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 @@ import java.util.function.Consumer; */ 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 @@ class ShareTargetPredictor extends AppTargetPredictor { @WorkerThread @Override void reportAppTargetEvent(AppTargetEvent event) { + if (DEBUG) { + Slog.d(TAG, "reportAppTargetEvent"); + } getDataManager().reportShareTargetEvent(event, mIntentFilter); } @@ -66,6 +73,9 @@ class ShareTargetPredictor extends AppTargetPredictor { @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 @@ class ShareTargetPredictor extends AppTargetPredictor { @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 @@ class ShareTargetPredictor extends AppTargetPredictor { 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 0ac5724210da..76f252efb412 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 @@ class SharesheetModelScorer { 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 @@ class SharesheetModelScorer { 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 @@ class SharesheetModelScorer { 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 aad24d72345b..93b5ef040926 100644 --- a/services/print/Android.bp +++ b/services/print/Android.bp @@ -7,6 +7,7 @@ filegroup { 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 805858f7f654..28830956e7f5 100644 --- a/services/restrictions/Android.bp +++ b/services/restrictions/Android.bp @@ -7,6 +7,7 @@ filegroup { 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 093b4ec66ddf..46a81aae63c5 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 1ce3e665c665..54968c003560 100644 --- a/services/systemcaptions/Android.bp +++ b/services/systemcaptions/Android.bp @@ -7,6 +7,7 @@ filegroup { java_library_static { name: "services.systemcaptions", + defaults: ["services_defaults"], srcs: [":services.systemcaptions-sources"], libs: ["services.core"], } diff --git a/services/tests/servicestests/assets/AppIntegrityManagerServiceImplTest/AppIntegrityManagerServiceTestApp.apk b/services/tests/servicestests/assets/AppIntegrityManagerServiceImplTest/AppIntegrityManagerServiceTestApp.apk Binary files differindex cc1f68cbf6f0..ff25a4a9a02d 100644 --- a/services/tests/servicestests/assets/AppIntegrityManagerServiceImplTest/AppIntegrityManagerServiceTestApp.apk +++ b/services/tests/servicestests/assets/AppIntegrityManagerServiceImplTest/AppIntegrityManagerServiceTestApp.apk 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 41142f6b8505..98bc0673f79c 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 @@ public class AppOpsActiveWatcherTest { // 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 96f329b9161e..1e602f84071d 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 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.runner.AndroidJUnit4; import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + 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.verifyNoMoreInteractions; - /** * Tests watching noted ops. */ @@ -77,6 +77,27 @@ public class AppOpsNotedWatcherTest { // 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 000000000000..1aa697b04f1d --- /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/integrity/AppIntegrityManagerServiceImplTest.java b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java index 9c2ef4fcc1be..53c9bb22e752 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 @@ public class AppIntegrityManagerServiceImplTest { // 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/people/prediction/ShareTargetPredictorTest.java b/services/tests/servicestests/src/com/android/server/people/prediction/ShareTargetPredictorTest.java index 1480627b9b9f..c2716393b947 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 @@ public final class ShareTargetPredictorTest { 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 9d96d6b7d861..9fc17763b8e0 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 @@ public final class SharesheetModelScorerTest { 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 d4edab44bae3..63d797e9b95c 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 @@ public class PackageInstallerSessionTest { /* 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 0a68688cef9e..37c106094954 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 class PackageManagerServiceTest { 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 daaf870fa695..b0b5386a49bd 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 @@ public class PackageParserTest { @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/dex/DexMetadataHelperTest.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java index 3888ff3e278a..caa8ae5e0e39 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.ApkLite; 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 @@ public class DexMetadataHelperTest { 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 6de08fd1251f..086c845fa4b6 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 @@ -30,10 +30,8 @@ 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 @@ -63,27 +61,7 @@ open class AndroidPackageParsingTestBase { 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. 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 939b7a0beb49..bb223b33d8aa 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.PackageInfo; 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 @@ public class PackageParserLegacyCoreTest { 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 22487071cd71..d8910dec0bcc 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 @@ class PackageParsingDeferErrorTest { } } - 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 @@ class PackageParsingDeferErrorTest { 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 21af3563b869..f9343236662b 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 @@ public class TunerResourceManagerServiceTest { 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 @@ public class TunerResourceManagerServiceTest { 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 @@ public class TunerResourceManagerServiceTest { .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 0e48e7ed2682..e86399e1a631 100644 --- a/services/tests/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java @@ -171,7 +171,7 @@ public class UriGrantsManagerServiceTest { 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 39062f017a73..6718db768fdb 100644 --- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java +++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java @@ -366,29 +366,87 @@ public class AppStandbyControllerTests { 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 +454,17 @@ public class AppStandbyControllerTests { 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)); 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 bda0c610fa12..babe80e4b612 100755 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -4932,7 +4932,32 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { 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)); } 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 cba89d0aea2d..ac95a817bec9 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.same; 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 @@ public class DisplayContentTests extends WindowTestsBase { 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 @@ public class DisplayContentTests extends WindowTestsBase { // 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/DisplayPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java index d0fd50dc497b..c2db0c09f88a 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_FOCUSABLE; 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 @@ public class DisplayPolicyTests extends WindowTestsBase { 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/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java index ea933dfe42dc..5005c07832ab 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.anyBoolean; 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 @@ public class RecentTasksTest extends ActivityTestsBase { } @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/usage/Android.bp b/services/usage/Android.bp index 156bf330c128..463673f104ab 100644 --- a/services/usage/Android.bp +++ b/services/usage/Android.bp @@ -7,6 +7,7 @@ filegroup { java_library_static { name: "services.usage", + defaults: ["services_defaults"], srcs: [":services.usage-sources"], libs: ["services.core"], } diff --git a/services/usb/Android.bp b/services/usb/Android.bp index a9474c10017e..4e984093cfec 100644 --- a/services/usb/Android.bp +++ b/services/usb/Android.bp @@ -7,6 +7,7 @@ filegroup { 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 85b96f34f4f6..47129ad62e86 100644 --- a/services/voiceinteraction/Android.bp +++ b/services/voiceinteraction/Android.bp @@ -7,6 +7,7 @@ filegroup { java_library_static { name: "services.voiceinteraction", + defaults: ["services_defaults"], srcs: [":services.voiceinteraction-sources"], libs: ["services.core"], } diff --git a/services/wifi/Android.bp b/services/wifi/Android.bp index f56c2cf76956..3975fd238bb5 100644 --- a/services/wifi/Android.bp +++ b/services/wifi/Android.bp @@ -7,6 +7,7 @@ filegroup { java_library_static { name: "services.wifi", + defaults: ["services_defaults"], srcs: [ ":services.wifi-sources", ], diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java index a716b37f7efd..56cba1d3f913 100755 --- a/telecomm/java/android/telecom/ConnectionService.java +++ b/telecomm/java/android/telecom/ConnectionService.java @@ -2102,12 +2102,12 @@ public abstract class ConnectionService extends Service { 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 @@ public abstract class ConnectionService extends Service { } 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 @@ public abstract class ConnectionService extends Service { } 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 @@ public abstract class ConnectionService extends Service { } 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 @@ public abstract class ConnectionService extends Service { } 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 @@ public abstract class ConnectionService extends Service { } 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 @@ public abstract class ConnectionService extends Service { } 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 @@ public abstract class ConnectionService extends Service { } 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 @@ public abstract class ConnectionService extends Service { } 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 @@ public abstract class ConnectionService extends Service { } 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 @@ public abstract class ConnectionService extends Service { } 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 @@ public abstract class ConnectionService extends Service { } 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 @@ public abstract class ConnectionService extends Service { } 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 @@ public abstract class ConnectionService extends Service { } 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 @@ public abstract class ConnectionService extends Service { * @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 @@ public abstract class ConnectionService extends Service { * @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 @@ public abstract class ConnectionService extends Service { * @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 @@ public abstract class ConnectionService extends Service { * @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 @@ public abstract class ConnectionService extends Service { } 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 @@ public abstract class ConnectionService extends Service { } 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 @@ public abstract class ConnectionService extends Service { } 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 @@ public abstract class ConnectionService extends Service { } 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 4f6a9d6450f8..a90d0532b721 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 android.text.TextUtils; 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 @@ public class Log { 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 @@ public class Log { } 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 8d3f4e1df8bc..4aa3614fa004 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 class Session { 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 @@ public class Session { // 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 class Session { 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 class Session { public void writeToParcel(Parcel destination, int flags) { destination.writeString(sessionId); destination.writeString(methodPath); + destination.writeString(ownerInfo); } } @@ -206,6 +232,14 @@ public class Session { 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 ac300587cef8..67e5eabf54eb 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 @@ public class SessionManager { 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 @@ public class SessionManager { // 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 @@ public class SessionManager { 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 @@ public class SessionManager { "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 05480dc38a0d..f947d34e5baf 100644 --- a/telecomm/java/android/telecom/RemoteConnection.java +++ b/telecomm/java/android/telecom/RemoteConnection.java @@ -30,13 +30,16 @@ import android.os.Bundle; 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 @@ public final class RemoteConnection { private int mCallerDisplayNamePresentation; private RemoteConference mConference; private Bundle mExtras; + private String mCallingPackage; + private String mCallingPackageAbbreviation; /** * @hide @@ -667,6 +672,13 @@ public final class RemoteConnection { 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 @@ public final class RemoteConnection { Bundle newExtras = new Bundle(); newExtras.putString(Connection.EXTRA_ORIGINAL_CONNECTION_ID, callId); putExtras(newExtras); + mCallingPackage = callingPackage; + mCallingPackageAbbreviation = Log.getPackageAbbreviation(mCallingPackage); } /** @@ -899,11 +913,14 @@ public final class RemoteConnection { * 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 @@ public final class RemoteConnection { * 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 @@ public final class RemoteConnection { * @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 @@ public final class RemoteConnection { * 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 @@ public final class RemoteConnection { * 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 @@ public final class RemoteConnection { * 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 @@ public final class RemoteConnection { * 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 @@ public final class RemoteConnection { * 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 @@ public final class RemoteConnection { * 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 @@ public final class RemoteConnection { * @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 @@ public final class RemoteConnection { * 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 @@ public final class RemoteConnection { * @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 @@ public final class RemoteConnection { * @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 @@ public final class RemoteConnection { * @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 @@ public final class RemoteConnection { * 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 @@ public final class RemoteConnection { } } } catch (RemoteException ignored) { + } finally { + Log.endSession(); } } @@ -1164,6 +1225,22 @@ public final class RemoteConnection { 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/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index 45dc7afc3dc0..e9ee06c246ba 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -63,6 +63,7 @@ import com.android.internal.telephony.ISetOpportunisticDataCallback; 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 class SubscriptionManager { 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; + + 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 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(); - }}; + 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 @@ public class SubscriptionManager { } return subInfo; - } /** @@ -1769,25 +1864,7 @@ public class SubscriptionManager { * 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 @@ public class SubscriptionManager { /** @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 @@ public class SubscriptionManager { 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 @@ public class SubscriptionManager { * @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 @@ public class SubscriptionManager { 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 @@ public class SubscriptionManager { * 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 @@ public class SubscriptionManager { 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/wifi/Android.bp b/wifi/Android.bp index 6a8600a5baa4..1e2c81a60178 100644 --- a/wifi/Android.bp +++ b/wifi/Android.bp @@ -143,6 +143,16 @@ droidstubs { "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 { @@ -151,6 +161,16 @@ droidstubs { "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 { @@ -159,6 +179,15 @@ droidstubs { "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 { diff --git a/wifi/api/lint-baseline.txt b/wifi/api/lint-baseline.txt new file mode 100644 index 000000000000..892411f8c3a1 --- /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 000000000000..6547ee8a2188 --- /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 e55a89fddd0c..26927e56d2fa 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.Layer2InformationParcelable* com.android.wifi.x.@0 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 |