diff options
521 files changed, 11921 insertions, 5727 deletions
diff --git a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShimPriv_apk.asciipb b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShimPriv_apk.asciipb index 78c48200cfc5..3258514cb6d7 100644 --- a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShimPriv_apk.asciipb +++ b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShimPriv_apk.asciipb @@ -1,6 +1,6 @@ drops { android_build_drop { - build_id: "7471822" + build_id: "7533747" target: "CtsShim" source_file: "aosp_arm64/CtsShimPriv.apk" } diff --git a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShim_apk.asciipb b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShim_apk.asciipb index a9632ad05ac0..4fb50e22989c 100644 --- a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShim_apk.asciipb +++ b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShim_apk.asciipb @@ -1,6 +1,6 @@ drops { android_build_drop { - build_id: "7471822" + build_id: "7533747" target: "CtsShim" source_file: "aosp_arm64/CtsShim.apk" } diff --git a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShimPriv_apk.asciipb b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShimPriv_apk.asciipb index df3a0bbe9f2c..1a0e3185665a 100644 --- a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShimPriv_apk.asciipb +++ b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShimPriv_apk.asciipb @@ -1,6 +1,6 @@ drops { android_build_drop { - build_id: "7471822" + build_id: "7533747" target: "CtsShim" source_file: "aosp_x86_64/CtsShimPriv.apk" } diff --git a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShim_apk.asciipb b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShim_apk.asciipb index 1bc6cb8706f2..d72f62e52148 100644 --- a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShim_apk.asciipb +++ b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShim_apk.asciipb @@ -1,6 +1,6 @@ drops { android_build_drop { - build_id: "7471822" + build_id: "7533747" target: "CtsShim" source_file: "aosp_x86_64/CtsShim.apk" } diff --git a/apct-tests/perftests/multiuser/Android.bp b/apct-tests/perftests/multiuser/Android.bp index 917753e28829..c967e51e16f9 100644 --- a/apct-tests/perftests/multiuser/Android.bp +++ b/apct-tests/perftests/multiuser/Android.bp @@ -31,6 +31,6 @@ android_test { ], platform_apis: true, test_suites: ["device-tests"], - data: [":perfetto_artifacts"], + data: ["trace_configs/*"], certificate: "platform", } diff --git a/apct-tests/perftests/multiuser/AndroidManifest.xml b/apct-tests/perftests/multiuser/AndroidManifest.xml index 95533041323a..63e5983401d7 100644 --- a/apct-tests/perftests/multiuser/AndroidManifest.xml +++ b/apct-tests/perftests/multiuser/AndroidManifest.xml @@ -20,10 +20,12 @@ <uses-permission android:name="android.permission.CONTROL_KEYGUARD" /> <uses-permission android:name="android.permission.DEVICE_POWER" /> - <uses-permission android:name="android.permission.MANAGE_USERS" /> <uses-permission android:name="android.permission.INSTALL_PACKAGES" /> <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" /> <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" /> + <uses-permission android:name="android.permission.MANAGE_USERS" /> + <uses-permission android:name="android.permission.REAL_GET_TASKS" /> + <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" /> <application> diff --git a/apct-tests/perftests/multiuser/AndroidTest.xml b/apct-tests/perftests/multiuser/AndroidTest.xml index fbe589248338..8e342f3389fc 100644 --- a/apct-tests/perftests/multiuser/AndroidTest.xml +++ b/apct-tests/perftests/multiuser/AndroidTest.xml @@ -26,7 +26,7 @@ <!-- Needed for pushing the trace config file --> <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/> <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"> - <option name="push-file" key="trace_config_detailed.textproto" value="/data/misc/perfetto-traces/trace_config.textproto" /> + <option name="push-file" key="trace_config_multi_user.textproto" value="/data/misc/perfetto-traces/trace_config.textproto" /> <!--Install the content provider automatically when we push some file in sdcard folder.--> <!--Needed to avoid the installation during the test suite.--> <option name="push-file" key="trace_config_detailed.textproto" value="/sdcard/sample.textproto" /> diff --git a/apct-tests/perftests/multiuser/trace_configs/trace_config_multi_user.textproto b/apct-tests/perftests/multiuser/trace_configs/trace_config_multi_user.textproto new file mode 100644 index 000000000000..14a3f8f9245b --- /dev/null +++ b/apct-tests/perftests/multiuser/trace_configs/trace_config_multi_user.textproto @@ -0,0 +1,154 @@ +# Copyright (C) 2021 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# proto-message: TraceConfig + +# Enable periodic flushing of the trace buffer into the output file. +write_into_file: true + +# Writes the userspace buffer into the file every 1s. +file_write_period_ms: 1000 + +# See b/126487238 - we need to guarantee ordering of events. +flush_period_ms: 10000 + +# The trace buffers needs to be big enough to hold |file_write_period_ms| of +# trace data. The trace buffer sizing depends on the number of trace categories +# enabled and the device activity. + +# RSS events +buffers { + size_kb: 32768 + fill_policy: RING_BUFFER +} + +# procfs polling +buffers { + size_kb: 8192 + fill_policy: RING_BUFFER +} + +data_sources { + config { + name: "linux.ftrace" + target_buffer: 0 + ftrace_config { + # These parameters affect only the kernel trace buffer size and how + # frequently it gets moved into the userspace buffer defined above. + buffer_size_kb: 16384 + drain_period_ms: 250 + + # Store certain high-volume "sched" ftrace events in a denser format + # (falling back to the default format if not supported by the tracer). + compact_sched { + enabled: true + } + + # Enables symbol name resolution against /proc/kallsyms + symbolize_ksyms: true + + # We need to do process tracking to ensure kernel ftrace events targeted at short-lived + # threads are associated correctly + ftrace_events: "task/task_newtask" + ftrace_events: "task/task_rename" + ftrace_events: "sched/sched_process_exit" + ftrace_events: "sched/sched_process_free" + + # Memory events + ftrace_events: "rss_stat" + ftrace_events: "ion_heap_shrink" + ftrace_events: "ion_heap_grow" + ftrace_events: "ion/ion_stat" + ftrace_events: "dmabuf_heap/dma_heap_stat" + ftrace_events: "oom_score_adj_update" + ftrace_events: "gpu_mem/gpu_mem_total" + + # Old (kernel) LMK + ftrace_events: "lowmemorykiller/lowmemory_kill" + + atrace_apps: "*" + + atrace_categories: "am" + atrace_categories: "bionic" + atrace_categories: "camera" + atrace_categories: "wm" + atrace_categories: "dalvik" + atrace_categories: "sched" + atrace_categories: "freq" + atrace_categories: "gfx" + atrace_categories: "view" + atrace_categories: "webview" + atrace_categories: "input" + atrace_categories: "hal" + atrace_categories: "binder_driver" + atrace_categories: "sync" + atrace_categories: "workq" + atrace_categories: "res" + + } + } +} + +data_sources: { + config { + name: "android.gpu.memory" + target_buffer: 0 + } +} + +data_sources { + config { + name: "linux.process_stats" + target_buffer: 1 + process_stats_config { + proc_stats_poll_ms: 10000 + } + } +} + +data_sources { + config { + name: "linux.sys_stats" + target_buffer: 1 + sys_stats_config { + meminfo_period_ms: 1000 + meminfo_counters: MEMINFO_MEM_TOTAL + meminfo_counters: MEMINFO_MEM_FREE + meminfo_counters: MEMINFO_MEM_AVAILABLE + meminfo_counters: MEMINFO_BUFFERS + meminfo_counters: MEMINFO_CACHED + meminfo_counters: MEMINFO_SWAP_CACHED + meminfo_counters: MEMINFO_ACTIVE + meminfo_counters: MEMINFO_INACTIVE + meminfo_counters: MEMINFO_ACTIVE_ANON + meminfo_counters: MEMINFO_INACTIVE_ANON + meminfo_counters: MEMINFO_ACTIVE_FILE + meminfo_counters: MEMINFO_INACTIVE_FILE + meminfo_counters: MEMINFO_UNEVICTABLE + meminfo_counters: MEMINFO_SWAP_TOTAL + meminfo_counters: MEMINFO_SWAP_FREE + meminfo_counters: MEMINFO_DIRTY + meminfo_counters: MEMINFO_WRITEBACK + meminfo_counters: MEMINFO_ANON_PAGES + meminfo_counters: MEMINFO_MAPPED + meminfo_counters: MEMINFO_SHMEM + } + } +} + +data_sources: { + config: { + name: "android.surfaceflinger.frametimeline" + } +} diff --git a/apex/appsearch/service/Android.bp b/apex/appsearch/service/Android.bp index 5ab7ff9f13c0..b101895f82c9 100644 --- a/apex/appsearch/service/Android.bp +++ b/apex/appsearch/service/Android.bp @@ -51,6 +51,7 @@ java_library { ], libs: [ "framework-appsearch.impl", + "framework-statsd.stubs.module_lib", "unsupportedappusage", // TODO(b/181887768) should be removed ], defaults: ["framework-system-server-module-defaults"], diff --git a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchConfig.java b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchConfig.java index 689aa1fcd371..c44fd40617a1 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchConfig.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchConfig.java @@ -64,6 +64,12 @@ public final class AppSearchConfig implements AutoCloseable { static final int DEFAULT_LIMIT_CONFIG_MAX_DOCUMENT_SIZE_BYTES = 512 * 1024; // 512KiB @VisibleForTesting static final int DEFAULT_LIMIT_CONFIG_MAX_DOCUMENT_COUNT = 20_000; + @VisibleForTesting + static final int DEFAULT_BYTES_OPTIMIZE_THRESHOLD = 1 * 1024 * 1024; // 1 MiB + @VisibleForTesting + static final int DEFAULT_TIME_OPTIMIZE_THRESHOLD_MILLIS = Integer.MAX_VALUE; + @VisibleForTesting + static final int DEFAULT_DOC_COUNT_OPTIMIZE_THRESHOLD = 10_000; /* * Keys for ALL the flags stored in DeviceConfig. @@ -79,6 +85,9 @@ public final class AppSearchConfig implements AutoCloseable { "limit_config_max_document_size_bytes"; public static final String KEY_LIMIT_CONFIG_MAX_DOCUMENT_COUNT = "limit_config_max_document_docunt"; + public static final String KEY_BYTES_OPTIMIZE_THRESHOLD = "bytes_optimize_threshold"; + public static final String KEY_TIME_OPTIMIZE_THRESHOLD_MILLIS = "time_optimize_threshold"; + public static final String KEY_DOC_COUNT_OPTIMIZE_THRESHOLD = "doc_count_optimize_threshold"; // Array contains all the corresponding keys for the cached values. private static final String[] KEYS_TO_ALL_CACHED_VALUES = { @@ -88,6 +97,9 @@ public final class AppSearchConfig implements AutoCloseable { KEY_SAMPLING_INTERVAL_FOR_PUT_DOCUMENT_STATS, KEY_LIMIT_CONFIG_MAX_DOCUMENT_SIZE_BYTES, KEY_LIMIT_CONFIG_MAX_DOCUMENT_COUNT, + KEY_BYTES_OPTIMIZE_THRESHOLD, + KEY_TIME_OPTIMIZE_THRESHOLD_MILLIS, + KEY_DOC_COUNT_OPTIMIZE_THRESHOLD }; // Lock needed for all the operations in this class. @@ -251,6 +263,48 @@ public final class AppSearchConfig implements AutoCloseable { } } + /** + * Returns the cached optimize byte size threshold. + * + * An AppSearch Optimize job will be triggered if the bytes size of garbage resource exceeds + * this threshold. + */ + int getCachedBytesOptimizeThreshold() { + synchronized (mLock) { + throwIfClosedLocked(); + return mBundleLocked.getInt(KEY_BYTES_OPTIMIZE_THRESHOLD, + DEFAULT_BYTES_OPTIMIZE_THRESHOLD); + } + } + + /** + * Returns the cached optimize time interval threshold. + * + * An AppSearch Optimize job will be triggered if the time since last optimize job exceeds + * this threshold. + */ + int getCachedTimeOptimizeThresholdMs() { + synchronized (mLock) { + throwIfClosedLocked(); + return mBundleLocked.getInt(KEY_TIME_OPTIMIZE_THRESHOLD_MILLIS, + DEFAULT_TIME_OPTIMIZE_THRESHOLD_MILLIS); + } + } + + /** + * Returns the cached optimize document count threshold threshold. + * + * An AppSearch Optimize job will be triggered if the number of document of garbage resource + * exceeds this threshold. + */ + int getCachedDocCountOptimizeThreshold() { + synchronized (mLock) { + throwIfClosedLocked(); + return mBundleLocked.getInt(KEY_DOC_COUNT_OPTIMIZE_THRESHOLD, + DEFAULT_DOC_COUNT_OPTIMIZE_THRESHOLD); + } + } + @GuardedBy("mLock") private void throwIfClosedLocked() { if (mIsClosedLocked) { @@ -307,6 +361,24 @@ public final class AppSearchConfig implements AutoCloseable { properties.getInt(key, DEFAULT_LIMIT_CONFIG_MAX_DOCUMENT_COUNT)); } break; + case KEY_BYTES_OPTIMIZE_THRESHOLD: + synchronized (mLock) { + mBundleLocked.putInt(key, properties.getInt(key, + DEFAULT_BYTES_OPTIMIZE_THRESHOLD)); + } + break; + case KEY_TIME_OPTIMIZE_THRESHOLD_MILLIS: + synchronized (mLock) { + mBundleLocked.putInt(key, properties.getInt(key, + DEFAULT_TIME_OPTIMIZE_THRESHOLD_MILLIS)); + } + break; + case KEY_DOC_COUNT_OPTIMIZE_THRESHOLD: + synchronized (mLock) { + mBundleLocked.putInt(key, properties.getInt(key, + DEFAULT_DOC_COUNT_OPTIMIZE_THRESHOLD)); + } + break; default: break; } diff --git a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java index ec37c3f68aaa..b52a503a2166 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java @@ -61,6 +61,7 @@ import com.android.server.LocalManagerRegistry; import com.android.server.SystemService; import com.android.server.appsearch.external.localstorage.stats.CallStats; import com.android.server.appsearch.external.localstorage.visibilitystore.VisibilityStore; +import com.android.server.appsearch.stats.StatsCollector; import com.android.server.appsearch.util.PackageUtil; import com.android.server.usage.StorageStatsManagerLocal; import com.android.server.usage.StorageStatsManagerLocal.StorageStatsAugmenter; @@ -123,6 +124,13 @@ public class AppSearchManagerService extends SystemService { .registerStorageStatsAugmenter(new AppSearchStorageStatsAugmenter(), TAG); } + @Override + public void onBootPhase(/* @BootPhase */ int phase) { + if (phase == PHASE_BOOT_COMPLETED) { + StatsCollector.getInstance(mContext, EXECUTOR); + } + } + private void registerReceivers() { mContext.registerReceiverForAllUsers( new UserActionReceiver(), @@ -364,6 +372,12 @@ public class AppSearchManagerService extends SystemService { ++operationSuccessCount; invokeCallbackOnResult(callback, AppSearchResult.newSuccessfulResult(setSchemaResponse.getBundle())); + + // setSchema will sync the schemas in the request to AppSearch, any existing + // schemas which is not included in the request will be delete if we force + // override incompatible schemas. And all documents of these types will be + // deleted as well. We should checkForOptimize for these deletion. + checkForOptimize(instance); } catch (Throwable t) { ++operationFailureCount; statusCode = throwableToFailedResult(t).getResultCode(); @@ -505,6 +519,10 @@ public class AppSearchManagerService extends SystemService { // Now that the batch has been written. Persist the newly written data. instance.getAppSearchImpl().persistToDisk(PersistType.Code.LITE); invokeCallbackOnResult(callback, resultBuilder.build()); + + // The existing documents with same ID will be deleted, so there may be some + // resources that could be released after optimize(). + checkForOptimize(instance, /*mutateBatchSize=*/ documentBundles.size()); } catch (Throwable t) { ++operationFailureCount; statusCode = throwableToFailedResult(t).getResultCode(); @@ -1023,6 +1041,8 @@ public class AppSearchManagerService extends SystemService { // Now that the batch has been written. Persist the newly written data. instance.getAppSearchImpl().persistToDisk(PersistType.Code.LITE); invokeCallbackOnResult(callback, resultBuilder.build()); + + checkForOptimize(instance, ids.size()); } catch (Throwable t) { ++operationFailureCount; statusCode = throwableToFailedResult(t).getResultCode(); @@ -1092,6 +1112,8 @@ public class AppSearchManagerService extends SystemService { instance.getAppSearchImpl().persistToDisk(PersistType.Code.LITE); ++operationSuccessCount; invokeCallbackOnResult(callback, AppSearchResult.newSuccessfulResult(null)); + + checkForOptimize(instance); } catch (Throwable t) { ++operationFailureCount; statusCode = throwableToFailedResult(t).getResultCode(); @@ -1472,4 +1494,24 @@ public class AppSearchManagerService extends SystemService { } } } + + private void checkForOptimize(AppSearchUserInstance instance, int mutateBatchSize) { + EXECUTOR.execute(() -> { + try { + instance.getAppSearchImpl().checkForOptimize(mutateBatchSize); + } catch (AppSearchException e) { + Log.w(TAG, "Error occurred when check for optimize", e); + } + }); + } + + private void checkForOptimize(AppSearchUserInstance instance) { + EXECUTOR.execute(() -> { + try { + instance.getAppSearchImpl().checkForOptimize(); + } catch (AppSearchException e) { + Log.w(TAG, "Error occurred when check for optimize", e); + } + }); + } } diff --git a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchUserInstanceManager.java b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchUserInstanceManager.java index d0d2e8964cf0..529f2b04f600 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchUserInstanceManager.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchUserInstanceManager.java @@ -27,12 +27,13 @@ import android.util.Log; import com.android.internal.annotations.GuardedBy; import com.android.server.appsearch.external.localstorage.AppSearchImpl; -import com.android.server.appsearch.external.localstorage.FrameworkOptimizeStrategy; import com.android.server.appsearch.external.localstorage.stats.InitializeStats; import com.android.server.appsearch.stats.PlatformLogger; import com.android.server.appsearch.visibilitystore.VisibilityStoreImpl; import java.io.File; +import java.util.ArrayList; +import java.util.List; import java.util.Map; import java.util.Objects; @@ -158,6 +159,18 @@ public final class AppSearchUserInstanceManager { } } + /** + * Returns the list of all {@link UserHandle}s. + * + * <p>It can return an empty list if there is no {@link AppSearchUserInstance} created yet. + */ + @NonNull + public List<UserHandle> getAllUserHandles() { + synchronized (mInstancesLocked) { + return new ArrayList<>(mInstancesLocked.keySet()); + } + } + @NonNull private AppSearchUserInstance createUserInstance( @NonNull Context userContext, @@ -177,7 +190,7 @@ public final class AppSearchUserInstanceManager { icingDir, new FrameworkLimitConfig(config), initStatsBuilder, - new FrameworkOptimizeStrategy()); + new FrameworkOptimizeStrategy(config)); long prepareVisibilityStoreLatencyStartMillis = SystemClock.elapsedRealtime(); VisibilityStoreImpl visibilityStore = diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/FrameworkOptimizeStrategy.java b/apex/appsearch/service/java/com/android/server/appsearch/FrameworkOptimizeStrategy.java index 8ec30e186306..d9344493ac34 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/FrameworkOptimizeStrategy.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/FrameworkOptimizeStrategy.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 The Android Open Source Project + * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,14 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.server.appsearch.external.localstorage; +package com.android.server.appsearch; import android.annotation.NonNull; -import com.android.internal.annotations.VisibleForTesting; +import com.android.server.appsearch.external.localstorage.AppSearchImpl; +import com.android.server.appsearch.external.localstorage.OptimizeStrategy; import com.google.android.icing.proto.GetOptimizeInfoResultProto; +import java.util.Objects; + /** * An implementation of {@link OptimizeStrategy} will determine when to trigger {@link * AppSearchImpl#optimize()} in Jetpack environment. @@ -28,17 +31,18 @@ import com.google.android.icing.proto.GetOptimizeInfoResultProto; * @hide */ public class FrameworkOptimizeStrategy implements OptimizeStrategy { - - @VisibleForTesting static final int DOC_COUNT_OPTIMIZE_THRESHOLD = 100_000; - @VisibleForTesting static final int BYTES_OPTIMIZE_THRESHOLD = 1 * 1024 * 1024 * 1024; // 1GB - - @VisibleForTesting - static final long TIME_OPTIMIZE_THRESHOLD_MILLIS = 7 * 24 * 60 * 60 * 1000; // 1 week + private final AppSearchConfig mAppSearchConfig; + FrameworkOptimizeStrategy(@NonNull AppSearchConfig config) { + mAppSearchConfig = Objects.requireNonNull(config); + } @Override public boolean shouldOptimize(@NonNull GetOptimizeInfoResultProto optimizeInfo) { - return optimizeInfo.getOptimizableDocs() >= DOC_COUNT_OPTIMIZE_THRESHOLD - || optimizeInfo.getEstimatedOptimizableBytes() >= BYTES_OPTIMIZE_THRESHOLD - || optimizeInfo.getTimeSinceLastOptimizeMs() >= TIME_OPTIMIZE_THRESHOLD_MILLIS; + return optimizeInfo.getOptimizableDocs() + >= mAppSearchConfig.getCachedDocCountOptimizeThreshold() + || optimizeInfo.getEstimatedOptimizableBytes() + >= mAppSearchConfig.getCachedBytesOptimizeThreshold() + || optimizeInfo.getTimeSinceLastOptimizeMs() + >= mAppSearchConfig.getCachedTimeOptimizeThresholdMs(); } } diff --git a/apex/appsearch/service/java/com/android/server/appsearch/stats/PlatformLogger.java b/apex/appsearch/service/java/com/android/server/appsearch/stats/PlatformLogger.java index 322bd119b604..2cbce106932d 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/stats/PlatformLogger.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/stats/PlatformLogger.java @@ -45,7 +45,7 @@ import java.util.Objects; import java.util.Random; /** - * Logger Implementation using Westworld. + * Logger Implementation for pushed atoms. * * <p>This class is thread-safe. * @@ -95,7 +95,7 @@ public final class PlatformLogger implements AppSearchLogger { private long mLastPushTimeMillisLocked = 0; /** - * Helper class to hold platform specific stats for Westworld. + * Helper class to hold platform specific stats for statsd. */ static final class ExtraStats { // UID for the calling package of the stats. @@ -113,7 +113,7 @@ public final class PlatformLogger implements AppSearchLogger { } /** - * Westworld constructor + * Constructor */ public PlatformLogger( @NonNull Context userContext, @@ -203,7 +203,7 @@ public final class PlatformLogger implements AppSearchLogger { stats.getNumOperationsSucceeded(), stats.getNumOperationsFailed()); } catch (NoSuchAlgorithmException | UnsupportedEncodingException e) { - // TODO(b/184204720) report hashing error to Westworld + // TODO(b/184204720) report hashing error to statsd // We need to set a special value(e.g. 0xFFFFFFFF) for the hashing of the database, // so in the dashboard we know there is some error for hashing. // @@ -240,7 +240,7 @@ public final class PlatformLogger implements AppSearchLogger { stats.getNativeNumTokensIndexed(), stats.getNativeExceededMaxNumTokens()); } catch (NoSuchAlgorithmException | UnsupportedEncodingException e) { - // TODO(b/184204720) report hashing error to Westworld + // TODO(b/184204720) report hashing error to statsd // We need to set a special value(e.g. 0xFFFFFFFF) for the hashing of the database, // so in the dashboard we know there is some error for hashing. // @@ -286,7 +286,7 @@ public final class PlatformLogger implements AppSearchLogger { stats.getDocumentRetrievingLatencyMillis(), stats.getResultWithSnippetsCount()); } catch (NoSuchAlgorithmException | UnsupportedEncodingException e) { - // TODO(b/184204720) report hashing error to Westworld + // TODO(b/184204720) report hashing error to statsd // We need to set a special value(e.g. 0xFFFFFFFF) for the hashing of the database, // so in the dashboard we know there is some error for hashing. // @@ -363,7 +363,7 @@ public final class PlatformLogger implements AppSearchLogger { /** * Creates {@link ExtraStats} to hold additional information generated for logging. * - * <p>This method is called by most of logToWestworldLocked functions to reduce code + * <p>This method is called by most of logStatsImplLocked functions to reduce code * duplication. */ // TODO(b/173532925) Once we add CTS test for logging atoms and can inspect the result, we can diff --git a/apex/appsearch/service/java/com/android/server/appsearch/stats/StatsCollector.java b/apex/appsearch/service/java/com/android/server/appsearch/stats/StatsCollector.java new file mode 100644 index 000000000000..dd56739cde57 --- /dev/null +++ b/apex/appsearch/service/java/com/android/server/appsearch/stats/StatsCollector.java @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.appsearch.stats; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.UserIdInt; +import android.app.StatsManager; +import android.content.Context; +import android.os.UserHandle; +import android.util.Log; +import android.util.StatsEvent; + +import com.android.server.appsearch.AppSearchUserInstance; +import com.android.server.appsearch.AppSearchUserInstanceManager; + +import com.google.android.icing.proto.DocumentStorageInfoProto; +import com.google.android.icing.proto.IndexStorageInfoProto; +import com.google.android.icing.proto.SchemaStoreStorageInfoProto; +import com.google.android.icing.proto.StorageInfoProto; + +import java.util.List; +import java.util.Objects; +import java.util.concurrent.Executor; + +/** + * Implements statsd pullers for AppSearch. + * + * <p>This class registers pullers to statsd, which will be called once a day to obtain AppSearch + * statistics that cannot be sent to statsd in real time by {@link PlatformLogger}. + * + * @hide + */ +public final class StatsCollector implements StatsManager.StatsPullAtomCallback { + private static final String TAG = "AppSearchStatsCollector"; + + private static volatile StatsCollector sStatsCollector; + private final StatsManager mStatsManager; + + /** + * Gets an instance of {@link StatsCollector} to be used. + * + * <p>If no instance has been initialized yet, a new one will be created. Otherwise, the + * existing instance will be returned. + */ + @NonNull + public static StatsCollector getInstance(@NonNull Context context, + @NonNull Executor executor) { + Objects.requireNonNull(context); + Objects.requireNonNull(executor); + if (sStatsCollector == null) { + synchronized (StatsCollector.class) { + if (sStatsCollector == null) { + sStatsCollector = new StatsCollector(context, executor); + } + } + } + return sStatsCollector; + } + + private StatsCollector(@NonNull Context context, @NonNull Executor executor) { + mStatsManager = context.getSystemService(StatsManager.class); + if (mStatsManager != null) { + registerAtom(AppSearchStatsLog.APP_SEARCH_STORAGE_INFO, /*policy=*/ null, executor); + Log.d(TAG, "atoms registered"); + } else { + Log.e(TAG, "could not get StatsManager, atoms not registered"); + } + } + + /** + * {@inheritDoc} + * + * @return {@link StatsManager#PULL_SUCCESS} with list of atoms (potentially empty) if pull + * succeeded, {@link StatsManager#PULL_SKIP} if pull was too frequent or atom ID is + * unexpected. + */ + @Override + public int onPullAtom(int atomTag, @NonNull List<StatsEvent> data) { + Objects.requireNonNull(data); + switch (atomTag) { + case AppSearchStatsLog.APP_SEARCH_STORAGE_INFO: + return pullAppSearchStorageInfo(data); + default: + Log.e(TAG, "unexpected atom ID " + atomTag); + return StatsManager.PULL_SKIP; + } + } + + private static int pullAppSearchStorageInfo(@NonNull List<StatsEvent> data) { + AppSearchUserInstanceManager userInstanceManager = + AppSearchUserInstanceManager.getInstance(); + List<UserHandle> userHandles = userInstanceManager.getAllUserHandles(); + for (int i = 0; i < userHandles.size(); i++) { + UserHandle userHandle = userHandles.get(i); + try { + AppSearchUserInstance userInstance = userInstanceManager.getUserInstance( + userHandle); + StorageInfoProto storageInfoProto = + userInstance.getAppSearchImpl().getRawStorageInfoProto(); + data.add(buildStatsEvent(userHandle.getIdentifier(), storageInfoProto)); + } catch (Throwable t) { + Log.e(TAG, + "Failed to pull the storage info for user " + userHandle.toString(), + t); + } + } + + // Skip the report if there is no data. + if (data.isEmpty()) { + return StatsManager.PULL_SKIP; + } + + return StatsManager.PULL_SUCCESS; + } + + /** + * Registers and configures the callback for the pulled atom. + * + * @param atomId The id of the atom + * @param policy Optional metadata specifying the timeout, cool down time etc. statsD would + * use default values if it is null + * @param executor The executor in which to run the callback + */ + private void registerAtom(int atomId, @Nullable StatsManager.PullAtomMetadata policy, + @NonNull Executor executor) { + mStatsManager.setPullAtomCallback(atomId, policy, executor, /*callback=*/this); + } + + private static StatsEvent buildStatsEvent(@UserIdInt int userId, + @NonNull StorageInfoProto storageInfoProto) { + return AppSearchStatsLog.buildStatsEvent( + AppSearchStatsLog.APP_SEARCH_STORAGE_INFO, + userId, + storageInfoProto.getTotalStorageSize(), + getDocumentStorageInfoBytes(storageInfoProto.getDocumentStorageInfo()), + getSchemaStoreStorageInfoBytes(storageInfoProto.getSchemaStoreStorageInfo()), + getIndexStorageInfoBytes(storageInfoProto.getIndexStorageInfo())); + } + + private static byte[] getDocumentStorageInfoBytes( + @NonNull DocumentStorageInfoProto proto) { + // Make sure we only log the fields defined in the atom in case new fields are added in + // IcingLib + DocumentStorageInfoProto.Builder builder = DocumentStorageInfoProto.newBuilder(); + builder.setNumAliveDocuments(proto.getNumAliveDocuments()) + .setNumDeletedDocuments(proto.getNumDeletedDocuments()) + .setNumExpiredDocuments(proto.getNumExpiredDocuments()) + .setDocumentStoreSize(proto.getDocumentStoreSize()) + .setDocumentLogSize(proto.getDocumentLogSize()) + .setKeyMapperSize(proto.getKeyMapperSize()) + .setDocumentIdMapperSize(proto.getDocumentIdMapperSize()) + .setScoreCacheSize(proto.getScoreCacheSize()) + .setFilterCacheSize(proto.getFilterCacheSize()) + .setCorpusMapperSize(proto.getCorpusMapperSize()) + .setCorpusScoreCacheSize(proto.getCorpusScoreCacheSize()) + .setNamespaceIdMapperSize(proto.getNamespaceIdMapperSize()) + .setNumNamespaces(proto.getNumNamespaces()); + return builder.build().toByteArray(); + } + + private static byte[] getSchemaStoreStorageInfoBytes( + @NonNull SchemaStoreStorageInfoProto proto) { + // Make sure we only log the fields defined in the atom in case new fields are added in + // IcingLib + SchemaStoreStorageInfoProto.Builder builder = SchemaStoreStorageInfoProto.newBuilder(); + builder.setSchemaStoreSize(proto.getSchemaStoreSize()) + .setNumSchemaTypes(proto.getNumSchemaTypes()) + .setNumTotalSections(proto.getNumTotalSections()) + .setNumSchemaTypesSectionsExhausted(proto.getNumSchemaTypesSectionsExhausted()); + return builder.build().toByteArray(); + } + + private static byte[] getIndexStorageInfoBytes( + @NonNull IndexStorageInfoProto proto) { + // Make sure we only log the fields defined in the atom in case new fields are added in + // IcingLib + IndexStorageInfoProto.Builder builder = IndexStorageInfoProto.newBuilder(); + builder.setIndexSize(proto.getIndexSize()) + .setLiteIndexLexiconSize(proto.getLiteIndexLexiconSize()) + .setLiteIndexHitBufferSize(proto.getLiteIndexHitBufferSize()) + .setMainIndexLexiconSize(proto.getMainIndexLexiconSize()) + .setMainIndexStorageSize(proto.getMainIndexStorageSize()) + .setMainIndexBlockSize(proto.getMainIndexBlockSize()) + .setNumBlocks(proto.getNumBlocks()) + .setMinFreeFraction(proto.getMinFreeFraction()); + return builder.build().toByteArray(); + } +} diff --git a/core/api/test-current.txt b/core/api/test-current.txt index ac02fe651892..2eafa9309998 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -333,8 +333,10 @@ package android.app { method public void clickNotification(@Nullable String, int, int, boolean); method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public void collapsePanels(); method public void expandNotificationsPanel(); + method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public void handleSystemKey(int); method public void sendNotificationFeedback(@Nullable String, @Nullable android.os.Bundle); method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public void setExpansionDisabledForSimNetworkLock(boolean); + method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public void togglePanel(); } public final class SyncNotedAppOp implements android.os.Parcelable { @@ -1048,8 +1050,16 @@ package android.graphics.fonts { package android.hardware { public final class SensorPrivacyManager { - method @RequiresPermission(android.Manifest.permission.MANAGE_SENSOR_PRIVACY) public void setSensorPrivacy(int, boolean); - method @RequiresPermission(android.Manifest.permission.MANAGE_SENSOR_PRIVACY) public void setSensorPrivacyForProfileGroup(int, boolean); + method @RequiresPermission(android.Manifest.permission.MANAGE_SENSOR_PRIVACY) public void setSensorPrivacy(int, int, boolean); + method @RequiresPermission(android.Manifest.permission.MANAGE_SENSOR_PRIVACY) public void setSensorPrivacyForProfileGroup(int, int, boolean); + } + + public static class SensorPrivacyManager.Sources { + field public static final int DIALOG = 3; // 0x3 + field public static final int OTHER = 5; // 0x5 + field public static final int QS_TILE = 1; // 0x1 + field public static final int SETTINGS = 2; // 0x2 + field public static final int SHELL = 4; // 0x4 } } @@ -2064,7 +2074,7 @@ package android.permission { public final class PermissionManager { method @NonNull @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) public java.util.List<android.permission.PermGroupUsage> getIndicatorAppOpUsageData(); method @NonNull @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) public java.util.List<android.permission.PermGroupUsage> getIndicatorAppOpUsageData(boolean); - method public void registerAttributionSource(@NonNull android.content.AttributionSource); + method @NonNull public android.content.AttributionSource registerAttributionSource(@NonNull android.content.AttributionSource); } } @@ -2163,7 +2173,6 @@ package android.provider { field @Deprecated public static final String ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES = "enabled_notification_policy_access_packages"; field public static final String ENABLED_VR_LISTENERS = "enabled_vr_listeners"; field public static final String IMMERSIVE_MODE_CONFIRMATIONS = "immersive_mode_confirmations"; - field public static final String NFC_PAYMENT_DEFAULT_COMPONENT = "nfc_payment_default_component"; field public static final String NOTIFICATION_BADGING = "notification_badging"; field public static final String NOTIFICATION_BUBBLES = "notification_bubbles"; field public static final String POWER_MENU_LOCKED_SHOW_CONTENT = "power_menu_locked_show_content"; @@ -2393,6 +2402,7 @@ package android.service.watchdog { package android.speech { public class SpeechRecognizer { + method @MainThread @NonNull public static android.speech.SpeechRecognizer createOnDeviceTestingSpeechRecognizer(@NonNull android.content.Context); method @RequiresPermission(android.Manifest.permission.MANAGE_SPEECH_RECOGNITION) public void setTemporaryOnDeviceRecognizer(@Nullable android.content.ComponentName); } diff --git a/core/java/android/app/ActivityClient.java b/core/java/android/app/ActivityClient.java index 633b986c06c9..bd4386885dd6 100644 --- a/core/java/android/app/ActivityClient.java +++ b/core/java/android/app/ActivityClient.java @@ -431,19 +431,6 @@ public class ActivityClient { } } - /** - * Restart the process and activity to adopt the latest configuration for size compat mode. - * This only takes effect for visible activity because invisible background activity can be - * restarted naturally when it becomes visible. - */ - public void restartActivityProcessIfVisible(IBinder token) { - try { - getActivityClientController().restartActivityProcessIfVisible(token); - } catch (RemoteException e) { - e.rethrowFromSystemServer(); - } - } - /** Removes the snapshot of home task. */ public void invalidateHomeTaskSnapshot(IBinder homeToken) { try { diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java index b7d9d9b67758..0d68df48c316 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -486,7 +486,7 @@ public abstract class ActivityManagerInternal { * not associated with an FGS; ensure display; or only update if already displayed. */ public abstract ServiceNotificationPolicy applyForegroundServiceNotification( - Notification notification, int id, String pkg, @UserIdInt int userId); + Notification notification, String tag, int id, String pkg, @UserIdInt int userId); /** * Callback from the notification subsystem that the given FGS notification has diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 64963031f1b3..249a60633ff0 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -2721,10 +2721,13 @@ class ContextImpl extends Context { // need to override their display in ResourcesManager. baseContext.mForceDisplayOverrideInResources = false; baseContext.mContextType = CONTEXT_TYPE_WINDOW_CONTEXT; - baseContext.mDisplay = display; final Resources windowContextResources = createWindowContextResources(baseContext); baseContext.setResources(windowContextResources); + // Associate the display with window context resources so that configuration update from + // the server side will also apply to the display's metrics. + baseContext.mDisplay = ResourcesManager.getInstance() + .getAdjustedDisplay(display.getDisplayId(), windowContextResources); return baseContext; } @@ -3149,7 +3152,8 @@ class ContextImpl extends Context { // If we want to access protected data on behalf of another app we need to // tell the OS that we opt in to participate in the attribution chain. if (nextAttributionSource != null) { - getSystemService(PermissionManager.class).registerAttributionSource(attributionSource); + attributionSource = getSystemService(PermissionManager.class) + .registerAttributionSource(attributionSource); } return attributionSource; } diff --git a/core/java/android/app/IActivityClientController.aidl b/core/java/android/app/IActivityClientController.aidl index 09b0c2f96b13..c6649692d848 100644 --- a/core/java/android/app/IActivityClientController.aidl +++ b/core/java/android/app/IActivityClientController.aidl @@ -117,16 +117,6 @@ interface IActivityClientController { oneway void setDisablePreviewScreenshots(in IBinder token, boolean disable); /** - * Restarts the activity by killing its process if it is visible. If the activity is not - * visible, the activity will not be restarted immediately and just keep the activity record in - * the stack. It also resets the current override configuration so the activity will use the - * configuration according to the latest state. - * - * @param activityToken The token of the target activity to restart. - */ - void restartActivityProcessIfVisible(in IBinder activityToken); - - /** * It should only be called from home activity to remove its outdated snapshot. The home * snapshot is used to speed up entering home from screen off. If the content of home activity * is significantly different from before taking the snapshot, then the home activity can use diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index 313a34067cd0..b90b9a11611e 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -508,7 +508,6 @@ interface IActivityManager { boolean stopBinderTrackingAndDump(in ParcelFileDescriptor fd); @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553) void suppressResizeConfigChanges(boolean suppress); - boolean isAppStartModeDisabled(int uid, in String packageName); @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553) boolean unlockUser(int userid, in byte[] token, in byte[] secret, in IProgressListener listener); diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl index 9f97fade6e98..2be78033ddf7 100644 --- a/core/java/android/app/IActivityTaskManager.aidl +++ b/core/java/android/app/IActivityTaskManager.aidl @@ -336,4 +336,12 @@ interface IActivityTaskManager { * TODO(188595497): Remove this once navbar attachment is in shell. */ void detachNavigationBarFromApp(in IBinder transition); + + /** + * Marks a process as a delegate for the currently playing remote transition animation. This + * must be called from a process that is already a remote transition player or delegate. Any + * marked delegates are cleaned-up automatically at the end of the transition. + * @param caller is the IApplicationThread representing the calling process. + */ + void setRunningRemoteTransitionDelegate(in IApplicationThread caller); } diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 6454d2027f58..9d149cf340e2 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -5380,14 +5380,15 @@ public class Notification implements Parcelable private void bindExpandButton(RemoteViews contentView, StandardTemplateParams p) { // set default colors - int textColor = getPrimaryTextColor(p); - int pillColor = getColors(p).getProtectionColor(); + int bgColor = getBackgroundColor(p); + int pillColor = Colors.flattenAlpha(getColors(p).getProtectionColor(), bgColor); + int textColor = Colors.flattenAlpha(getPrimaryTextColor(p), pillColor); contentView.setInt(R.id.expand_button, "setDefaultTextColor", textColor); contentView.setInt(R.id.expand_button, "setDefaultPillColor", pillColor); // Use different highlighted colors for conversations' unread count if (p.mHighlightExpander) { - textColor = getBackgroundColor(p); - pillColor = getPrimaryAccentColor(p); + pillColor = Colors.flattenAlpha(getPrimaryAccentColor(p), bgColor); + textColor = Colors.flattenAlpha(bgColor, pillColor); } contentView.setInt(R.id.expand_button, "setHighlightTextColor", textColor); contentView.setInt(R.id.expand_button, "setHighlightPillColor", pillColor); diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java index af75c6910fe1..bf3778dfeecc 100644 --- a/core/java/android/app/ResourcesManager.java +++ b/core/java/android/app/ResourcesManager.java @@ -1158,9 +1158,15 @@ public class ResourcesManager { } else { activityResources.overrideConfig.unset(); } + // Update the Activity's override display id. activityResources.overrideDisplayId = displayId; + // If a application info update was scheduled to occur in this process but has not + // occurred yet, apply it now so the resources objects will have updated paths if + // the assets sequence changed. + applyAllPendingAppInfoUpdates(); + if (DEBUG) { Throwable here = new Throwable(); here.fillInStackTrace(); diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java index 232b077538ef..77bcef3ae009 100644 --- a/core/java/android/app/StatusBarManager.java +++ b/core/java/android/app/StatusBarManager.java @@ -352,6 +352,42 @@ public class StatusBarManager { } /** + * Toggles the notification panel. + * + * @hide + */ + @RequiresPermission(android.Manifest.permission.STATUS_BAR) + @TestApi + public void togglePanel() { + try { + final IStatusBarService svc = getService(); + if (svc != null) { + svc.togglePanel(); + } + } catch (RemoteException ex) { + throw ex.rethrowFromSystemServer(); + } + } + + /** + * Sends system keys to the status bar. + * + * @hide + */ + @RequiresPermission(android.Manifest.permission.STATUS_BAR) + @TestApi + public void handleSystemKey(int key) { + try { + final IStatusBarService svc = getService(); + if (svc != null) { + svc.handleSystemKey(key); + } + } catch (RemoteException ex) { + throw ex.rethrowFromSystemServer(); + } + } + + /** * Expand the settings panel. * * @hide diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java index 3d32e00185ed..1569e6042ebf 100644 --- a/core/java/android/app/TaskInfo.java +++ b/core/java/android/app/TaskInfo.java @@ -194,13 +194,6 @@ public class TaskInfo { public ActivityInfo topActivityInfo; /** - * The top activity in this task. - * @hide - */ - @Nullable - public IBinder topActivityToken; - - /** * Whether the direct top activity is in size compat mode on foreground. * @hide */ @@ -370,12 +363,12 @@ public class TaskInfo { return displayId == that.displayId && taskId == that.taskId && topActivityInSizeCompat == that.topActivityInSizeCompat - // TopActivityToken and bounds are important if top activity is in size compat - && (!topActivityInSizeCompat || topActivityToken.equals(that.topActivityToken)) + // Bounds are important if top activity is in size compat && (!topActivityInSizeCompat || configuration.windowConfiguration.getBounds() .equals(that.configuration.windowConfiguration.getBounds())) && (!topActivityInSizeCompat || configuration.getLayoutDirection() - == that.configuration.getLayoutDirection()); + == that.configuration.getLayoutDirection()) + && (!topActivityInSizeCompat || isVisible == that.isVisible); } /** @@ -411,7 +404,6 @@ public class TaskInfo { isFocused = source.readBoolean(); isVisible = source.readBoolean(); isSleeping = source.readBoolean(); - topActivityToken = source.readStrongBinder(); topActivityInSizeCompat = source.readBoolean(); mTopActivityLocusId = source.readTypedObject(LocusId.CREATOR); displayAreaFeatureId = source.readInt(); @@ -451,7 +443,6 @@ public class TaskInfo { dest.writeBoolean(isFocused); dest.writeBoolean(isVisible); dest.writeBoolean(isSleeping); - dest.writeStrongBinder(topActivityToken); dest.writeBoolean(topActivityInSizeCompat); dest.writeTypedObject(mTopActivityLocusId, flags); dest.writeInt(displayAreaFeatureId); @@ -481,7 +472,6 @@ public class TaskInfo { + " isFocused=" + isFocused + " isVisible=" + isVisible + " isSleeping=" + isSleeping - + " topActivityToken=" + topActivityToken + " topActivityInSizeCompat=" + topActivityInSizeCompat + " locusId=" + mTopActivityLocusId + " displayAreaFeatureId=" + displayAreaFeatureId diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java index 421b4de9d626..f5ab2ab7448a 100644 --- a/core/java/android/bluetooth/BluetoothAdapter.java +++ b/core/java/android/bluetooth/BluetoothAdapter.java @@ -120,6 +120,7 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; */ public final class BluetoothAdapter { private static final String TAG = "BluetoothAdapter"; + private static final String DESCRIPTOR = "android.bluetooth.BluetoothAdapter"; private static final boolean DBG = true; private static final boolean VDBG = false; @@ -805,7 +806,7 @@ public final class BluetoothAdapter { mManagerService = Objects.requireNonNull(managerService); mAttributionSource = Objects.requireNonNull(attributionSource); mLeScanClients = new HashMap<LeScanCallback, ScanCallback>(); - mToken = new Binder(); + mToken = new Binder(DESCRIPTOR); } /** diff --git a/core/java/android/content/AttributionSource.java b/core/java/android/content/AttributionSource.java index 1dda6374a474..0e22705146af 100644 --- a/core/java/android/content/AttributionSource.java +++ b/core/java/android/content/AttributionSource.java @@ -86,6 +86,10 @@ import java.util.Set; */ @Immutable public final class AttributionSource implements Parcelable { + private static final String DESCRIPTOR = "android.content.AttributionSource"; + + private static final Binder sDefaultToken = new Binder(DESCRIPTOR); + private final @NonNull AttributionSourceState mAttributionSourceState; private @Nullable AttributionSource mNextCached; @@ -95,7 +99,7 @@ public final class AttributionSource implements Parcelable { @TestApi public AttributionSource(int uid, @Nullable String packageName, @Nullable String attributionTag) { - this(uid, packageName, attributionTag, new Binder()); + this(uid, packageName, attributionTag, sDefaultToken); } /** @hide */ @@ -130,7 +134,7 @@ public final class AttributionSource implements Parcelable { AttributionSource(int uid, @Nullable String packageName, @Nullable String attributionTag, @Nullable String[] renouncedPermissions, @Nullable AttributionSource next) { - this(uid, packageName, attributionTag, new Binder(), renouncedPermissions, next); + this(uid, packageName, attributionTag, sDefaultToken, renouncedPermissions, next); } AttributionSource(int uid, @Nullable String packageName, @Nullable String attributionTag, @@ -148,6 +152,10 @@ public final class AttributionSource implements Parcelable { AttributionSource(@NonNull Parcel in) { this(AttributionSourceState.CREATOR.createFromParcel(in)); + + // Since we just unpacked this object as part of it transiting a Binder + // call, this is the perfect time to enforce that its UID can be trusted + enforceCallingUid(); } /** @hide */ @@ -168,6 +176,12 @@ public final class AttributionSource implements Parcelable { } /** @hide */ + public AttributionSource withToken(@NonNull Binder token) { + return new AttributionSource(getUid(), getPackageName(), getAttributionTag(), + token, mAttributionSourceState.renouncedPermissions, getNext()); + } + + /** @hide */ public @NonNull AttributionSourceState asState() { return mAttributionSourceState; } @@ -541,7 +555,9 @@ public final class AttributionSource implements Parcelable { if ((mBuilderFieldsSet & 0x10) == 0) { mAttributionSourceState.next = null; } - mAttributionSourceState.token = new Binder(); + + mAttributionSourceState.token = sDefaultToken; + if (mAttributionSourceState.next == null) { // The NDK aidl backend doesn't support null parcelable arrays. mAttributionSourceState.next = new AttributionSourceState[0]; diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java index 60ab83aa2264..95c5612aeee4 100644 --- a/core/java/android/content/pm/ActivityInfo.java +++ b/core/java/android/content/pm/ActivityInfo.java @@ -1363,7 +1363,8 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { public boolean alwaysSandboxDisplayApis() { return CompatChanges.isChangeEnabled(ALWAYS_SANDBOX_DISPLAY_APIS, applicationInfo.packageName, - UserHandle.getUserHandleForUid(applicationInfo.uid)); + UserHandle.getUserHandleForUid(applicationInfo.uid)) + || ConstrainDisplayApisConfig.alwaysConstrainDisplayApis(applicationInfo); } /** @hide */ diff --git a/core/java/android/content/pm/ConstrainDisplayApisConfig.java b/core/java/android/content/pm/ConstrainDisplayApisConfig.java index 1337347cdaf0..11ba3d4ba9a2 100644 --- a/core/java/android/content/pm/ConstrainDisplayApisConfig.java +++ b/core/java/android/content/pm/ConstrainDisplayApisConfig.java @@ -47,6 +47,14 @@ public final class ConstrainDisplayApisConfig { "never_constrain_display_apis_all_packages"; /** + * A string flag whose value holds a comma separated list of package entries in the format + * '<package-name>:<min-version-code>?:<max-version-code>?' for which Display APIs should + * always be constrained. + */ + private static final String FLAG_ALWAYS_CONSTRAIN_DISPLAY_APIS = + "always_constrain_display_apis"; + + /** * Returns true if either the flag 'never_constrain_display_apis_all_packages' is true or the * flag 'never_constrain_display_apis' contains a package entry that matches the given {@code * applicationInfo}. @@ -58,8 +66,30 @@ public final class ConstrainDisplayApisConfig { FLAG_NEVER_CONSTRAIN_DISPLAY_APIS_ALL_PACKAGES, /* defaultValue= */ false)) { return true; } + + return flagHasMatchingPackageEntry(FLAG_NEVER_CONSTRAIN_DISPLAY_APIS, applicationInfo); + } + + /** + * Returns true if the flag 'always_constrain_display_apis' contains a package entry that + * matches the given {@code applicationInfo}. + * + * @param applicationInfo Information about the application/package. + */ + public static boolean alwaysConstrainDisplayApis(ApplicationInfo applicationInfo) { + return flagHasMatchingPackageEntry(FLAG_ALWAYS_CONSTRAIN_DISPLAY_APIS, applicationInfo); + } + + /** + * Returns true if the flag with the given {@code flagName} contains a package entry that + * matches the given {@code applicationInfo}. + * + * @param applicationInfo Information about the application/package. + */ + private static boolean flagHasMatchingPackageEntry(String flagName, + ApplicationInfo applicationInfo) { String configStr = DeviceConfig.getString(NAMESPACE_CONSTRAIN_DISPLAY_APIS, - FLAG_NEVER_CONSTRAIN_DISPLAY_APIS, /* defaultValue= */ ""); + flagName, /* defaultValue= */ ""); // String#split returns a non-empty array given an empty string. if (configStr.isEmpty()) { diff --git a/core/java/android/hardware/ISensorPrivacyManager.aidl b/core/java/android/hardware/ISensorPrivacyManager.aidl index 1c8e95917484..debc074ea21a 100644 --- a/core/java/android/hardware/ISensorPrivacyManager.aidl +++ b/core/java/android/hardware/ISensorPrivacyManager.aidl @@ -41,11 +41,11 @@ interface ISensorPrivacyManager { void setSensorPrivacy(boolean enable); - void setIndividualSensorPrivacy(int userId, int sensor, boolean enable); + void setIndividualSensorPrivacy(int userId, int source, int sensor, boolean enable); - void setIndividualSensorPrivacyForProfileGroup(int userId, int sensor, boolean enable); + void setIndividualSensorPrivacyForProfileGroup(int userId, int source, int sensor, boolean enable); // =============== End of transactions used on native side as well ============================ - void suppressIndividualSensorPrivacyReminders(int userId, String packageName, IBinder token, + void suppressIndividualSensorPrivacyReminders(int userId, int sensor, IBinder token, boolean suppress); }
\ No newline at end of file diff --git a/core/java/android/hardware/SensorPrivacyManager.java b/core/java/android/hardware/SensorPrivacyManager.java index 1a5e5a85d2a1..b7d95e7dea74 100644 --- a/core/java/android/hardware/SensorPrivacyManager.java +++ b/core/java/android/hardware/SensorPrivacyManager.java @@ -30,6 +30,7 @@ import android.os.IBinder; import android.os.RemoteException; import android.os.ServiceManager; import android.service.SensorPrivacyIndividualEnabledSensorProto; +import android.service.SensorPrivacyToggleSourceProto; import android.util.ArrayMap; import android.util.Pair; import android.util.SparseArray; @@ -41,11 +42,7 @@ import java.lang.annotation.RetentionPolicy; import java.util.concurrent.Executor; /** - * This class provides access to the sensor privacy services; sensor privacy allows the - * user to disable access to all sensors on the device. This class provides methods to query the - * current state of sensor privacy as well as to register / unregister for notification when - * the sensor privacy state changes. - * + * This class provides information about the microphone and camera toggles. */ @SystemService(Context.SENSOR_PRIVACY_SERVICE) public final class SensorPrivacyManager { @@ -103,6 +100,56 @@ public final class SensorPrivacyManager { } /** + * Source through which Privacy Sensor was toggled. + * @hide + */ + @TestApi + public static class Sources { + private Sources() {} + + /** + * Constant for the Quick Setting Tile. + */ + public static final int QS_TILE = SensorPrivacyToggleSourceProto.QS_TILE; + + /** + * Constant for the Settings. + */ + public static final int SETTINGS = SensorPrivacyToggleSourceProto.SETTINGS; + + /** + * Constant for Dialog. + */ + public static final int DIALOG = SensorPrivacyToggleSourceProto.DIALOG; + + /** + * Constant for SHELL. + */ + public static final int SHELL = SensorPrivacyToggleSourceProto.SHELL; + + /** + * Constant for OTHER. + */ + public static final int OTHER = SensorPrivacyToggleSourceProto.OTHER; + + /** + * Source for toggling sensors + * + * @hide + */ + @IntDef(value = { + QS_TILE, + SETTINGS, + DIALOG, + SHELL, + OTHER + }) + @Retention(RetentionPolicy.SOURCE) + public @interface Source {} + + } + + /** * A class implementing this interface can register with the {@link * android.hardware.SensorPrivacyManager} to receive notification when the sensor privacy * state changes. @@ -343,8 +390,9 @@ public final class SensorPrivacyManager { */ @TestApi @RequiresPermission(Manifest.permission.MANAGE_SENSOR_PRIVACY) - public void setSensorPrivacy(@Sensors.Sensor int sensor, boolean enable) { - setSensorPrivacy(sensor, enable, mContext.getUserId()); + public void setSensorPrivacy(@Sources.Source int source, @Sensors.Sensor int sensor, + boolean enable) { + setSensorPrivacy(source, sensor, enable, mContext.getUserId()); } /** @@ -357,10 +405,10 @@ public final class SensorPrivacyManager { * @hide */ @RequiresPermission(Manifest.permission.MANAGE_SENSOR_PRIVACY) - public void setSensorPrivacy(@Sensors.Sensor int sensor, boolean enable, - @UserIdInt int userId) { + public void setSensorPrivacy(@Sources.Source int source, @Sensors.Sensor int sensor, + boolean enable, @UserIdInt int userId) { try { - mService.setIndividualSensorPrivacy(userId, sensor, enable); + mService.setIndividualSensorPrivacy(userId, source, sensor, enable); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -370,6 +418,7 @@ public final class SensorPrivacyManager { * Sets sensor privacy to the specified state for an individual sensor for the profile group of * context's user. * + * @param source the source using which the sensor is toggled. * @param sensor the sensor which to change the state for * @param enable the state to which sensor privacy should be set. * @@ -377,15 +426,16 @@ public final class SensorPrivacyManager { */ @TestApi @RequiresPermission(Manifest.permission.MANAGE_SENSOR_PRIVACY) - public void setSensorPrivacyForProfileGroup(@Sensors.Sensor int sensor, - boolean enable) { - setSensorPrivacyForProfileGroup(sensor, enable, mContext.getUserId()); + public void setSensorPrivacyForProfileGroup(@Sources.Source int source, + @Sensors.Sensor int sensor, boolean enable) { + setSensorPrivacyForProfileGroup(source , sensor, enable, mContext.getUserId()); } /** * Sets sensor privacy to the specified state for an individual sensor for the profile group of * context's user. * + * @param source the source using which the sensor is toggled. * @param sensor the sensor which to change the state for * @param enable the state to which sensor privacy should be set. * @param userId the user's id @@ -393,11 +443,10 @@ public final class SensorPrivacyManager { * @hide */ @RequiresPermission(Manifest.permission.MANAGE_SENSOR_PRIVACY) - public void setSensorPrivacyForProfileGroup(@Sensors.Sensor int sensor, - boolean enable, @UserIdInt int userId) { + public void setSensorPrivacyForProfileGroup(@Sources.Source int source, + @Sensors.Sensor int sensor, boolean enable, @UserIdInt int userId) { try { - mService.setIndividualSensorPrivacyForProfileGroup(userId, sensor, - enable); + mService.setIndividualSensorPrivacyForProfileGroup(userId, source, sensor, enable); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -412,9 +461,9 @@ public final class SensorPrivacyManager { * @hide */ @RequiresPermission(Manifest.permission.MANAGE_SENSOR_PRIVACY) - public void suppressSensorPrivacyReminders(@NonNull String packageName, + public void suppressSensorPrivacyReminders(int sensor, boolean suppress) { - suppressSensorPrivacyReminders(packageName, suppress, mContext.getUserId()); + suppressSensorPrivacyReminders(sensor, suppress, mContext.getUserId()); } /** @@ -427,10 +476,10 @@ public final class SensorPrivacyManager { * @hide */ @RequiresPermission(Manifest.permission.MANAGE_SENSOR_PRIVACY) - public void suppressSensorPrivacyReminders(@NonNull String packageName, + public void suppressSensorPrivacyReminders(int sensor, boolean suppress, @UserIdInt int userId) { try { - mService.suppressIndividualSensorPrivacyReminders(userId, packageName, + mService.suppressIndividualSensorPrivacyReminders(userId, sensor, token, suppress); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java index 906256d70197..c78dd5366d31 100644 --- a/core/java/android/hardware/camera2/CaptureRequest.java +++ b/core/java/android/hardware/camera2/CaptureRequest.java @@ -2289,6 +2289,16 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>> * {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} is not 1.0, and {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} is set to be * windowboxing, the camera framework will override the {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} to be * the active array.</p> + * <p>In the capture request, if the application sets {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} to a + * value != 1.0, the {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} tag in the capture result reflects the + * effective zoom ratio achieved by the camera device, and the {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} + * adjusts for additional crops that are not zoom related. Otherwise, if the application + * sets {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} to 1.0, or does not set it at all, the + * {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} tag in the result metadata will also be 1.0.</p> + * <p>When the application requests a physical stream for a logical multi-camera, the + * {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} in the physical camera result metadata will be 1.0, and + * the {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} tag reflects the amount of zoom and crop done by the + * physical camera device.</p> * <p><b>Range of valid values:</b><br> * {@link CameraCharacteristics#CONTROL_ZOOM_RATIO_RANGE android.control.zoomRatioRange}</p> * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p> diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java index d32341fddff9..296bfbe2ba98 100644 --- a/core/java/android/hardware/camera2/CaptureResult.java +++ b/core/java/android/hardware/camera2/CaptureResult.java @@ -2567,6 +2567,16 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> { * {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} is not 1.0, and {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} is set to be * windowboxing, the camera framework will override the {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} to be * the active array.</p> + * <p>In the capture request, if the application sets {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} to a + * value != 1.0, the {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} tag in the capture result reflects the + * effective zoom ratio achieved by the camera device, and the {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} + * adjusts for additional crops that are not zoom related. Otherwise, if the application + * sets {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} to 1.0, or does not set it at all, the + * {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} tag in the result metadata will also be 1.0.</p> + * <p>When the application requests a physical stream for a logical multi-camera, the + * {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} in the physical camera result metadata will be 1.0, and + * the {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} tag reflects the amount of zoom and crop done by the + * physical camera device.</p> * <p><b>Range of valid values:</b><br> * {@link CameraCharacteristics#CONTROL_ZOOM_RATIO_RANGE android.control.zoomRatioRange}</p> * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p> diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java index 2e841f50e84d..6cbe107c96f5 100644 --- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java +++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java @@ -1873,6 +1873,8 @@ public class CameraMetadataNative implements Parcelable { private static synchronized native void nativeReadFromParcel(Parcel source, long ptr); private static synchronized native void nativeSwap(long ptr, long otherPtr) throws NullPointerException; + @FastNative + private static native void nativeSetVendorId(long ptr, long vendorId); private static synchronized native void nativeClose(long ptr); private static synchronized native boolean nativeIsEmpty(long ptr); private static synchronized native int nativeGetEntryCount(long ptr); @@ -1917,6 +1919,15 @@ public class CameraMetadataNative implements Parcelable { } /** + * Set the native metadata vendor id. + * + * @hide + */ + public void setVendorId(long vendorId) { + nativeSetVendorId(mMetadataPtr, vendorId); + } + + /** * @hide */ public int getEntryCount() { diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java index 0cb996b118b4..dc1a50fa6616 100644 --- a/core/java/android/hardware/fingerprint/FingerprintManager.java +++ b/core/java/android/hardware/fingerprint/FingerprintManager.java @@ -1382,12 +1382,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing String[] msgArray = context.getResources().getStringArray( com.android.internal.R.array.fingerprint_error_vendor); if (vendorCode < msgArray.length) { - if (Build.IS_ENG || Build.IS_USERDEBUG) { - return msgArray[vendorCode]; - } else { - return context.getString( - com.android.internal.R.string.fingerprint_error_unable_to_process); - } + return msgArray[vendorCode]; } } } @@ -1427,12 +1422,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing String[] msgArray = context.getResources().getStringArray( com.android.internal.R.array.fingerprint_acquired_vendor); if (vendorCode < msgArray.length) { - if (Build.IS_ENG || Build.IS_USERDEBUG) { - return msgArray[vendorCode]; - } else { - return context.getString( - com.android.internal.R.string.fingerprint_error_unable_to_process); - } + return msgArray[vendorCode]; } } break; diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java index 4ef0e6e785e8..a52ede87880e 100644 --- a/core/java/android/permission/PermissionManager.java +++ b/core/java/android/permission/PermissionManager.java @@ -44,6 +44,7 @@ import android.content.pm.PermissionGroupInfo; import android.content.pm.PermissionInfo; import android.content.pm.permission.SplitPermissionInfoParcelable; import android.media.AudioManager; +import android.os.Binder; import android.os.Build; import android.os.Handler; import android.os.Looper; @@ -1163,18 +1164,24 @@ public final class PermissionManager { * that doesn't participate in an attribution chain. * * @param source The attribution source to register. + * @return The registered new attribution source. * * @see #isRegisteredAttributionSource(AttributionSource) * * @hide */ @TestApi - public void registerAttributionSource(@NonNull AttributionSource source) { + public @NonNull AttributionSource registerAttributionSource(@NonNull AttributionSource source) { + // We use a shared static token for sources that are not registered since the token's + // only used for process death detection. If we are about to use the source for security + // enforcement we need to replace the binder with a unique one. + final AttributionSource registeredSource = source.withToken(new Binder()); try { - mPermissionManager.registerAttributionSource(source); + mPermissionManager.registerAttributionSource(registeredSource); } catch (RemoteException e) { e.rethrowFromSystemServer(); } + return registeredSource; } /** diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index a6332d76ca65..b191dfc561aa 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -8747,7 +8747,6 @@ public final class Settings { * @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @TestApi public static final String NFC_PAYMENT_DEFAULT_COMPONENT = "nfc_payment_default_component"; /** diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java index ff692818863a..ee8353a9f203 100644 --- a/core/java/android/service/notification/ZenModeConfig.java +++ b/core/java/android/service/notification/ZenModeConfig.java @@ -1969,7 +1969,17 @@ public class ZenModeConfig implements Parcelable { } public boolean isAutomaticActive() { - return enabled && !snoozing && pkg != null && isTrueOrUnknown(); + return enabled && !snoozing && getPkg() != null && isTrueOrUnknown(); + } + + public String getPkg() { + return !TextUtils.isEmpty(pkg) + ? pkg + : (component != null) + ? component.getPackageName() + : (configurationActivity != null) + ? configurationActivity.getPackageName() + : null; } public boolean isTrueOrUnknown() { diff --git a/core/java/android/service/voice/AbstractHotwordDetector.java b/core/java/android/service/voice/AbstractHotwordDetector.java index 54ccf309a58e..dbe108974684 100644 --- a/core/java/android/service/voice/AbstractHotwordDetector.java +++ b/core/java/android/service/voice/AbstractHotwordDetector.java @@ -20,7 +20,9 @@ import static com.android.internal.util.function.pooled.PooledLambda.obtainMessa import android.annotation.NonNull; import android.annotation.Nullable; +import android.app.ActivityThread; import android.media.AudioFormat; +import android.media.permission.Identity; import android.os.Handler; import android.os.Looper; import android.os.ParcelFileDescriptor; @@ -111,8 +113,10 @@ abstract class AbstractHotwordDetector implements HotwordDetector { if (DEBUG) { Slog.d(TAG, "updateStateLocked()"); } + Identity identity = new Identity(); + identity.packageName = ActivityThread.currentOpPackageName(); try { - mManagerService.updateState(options, sharedMemory, callback); + mManagerService.updateState(identity, options, sharedMemory, callback); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/service/voice/HotwordDetectedResult.java b/core/java/android/service/voice/HotwordDetectedResult.java index 5c660216065c..72341453a1f4 100644 --- a/core/java/android/service/voice/HotwordDetectedResult.java +++ b/core/java/android/service/voice/HotwordDetectedResult.java @@ -89,6 +89,12 @@ public final class HotwordDetectedResult implements Parcelable { /** Represents unset value for the triggered audio channel. */ public static final int AUDIO_CHANNEL_UNSET = -1; + /** Limits the max value for the hotword offset. */ + private static final int LIMIT_HOTWORD_OFFSET_MAX_VALUE = 60 * 60 * 1000; // 1 hour + + /** Limits the max value for the triggered audio channel. */ + private static final int LIMIT_AUDIO_CHANNEL_MAX_VALUE = 63; + /** Confidence level in the trigger outcome. */ @HotwordConfidenceLevelValue private final int mConfidenceLevel; @@ -107,6 +113,8 @@ public final class HotwordDetectedResult implements Parcelable { /** * Offset in milliseconds the audio stream when the trigger event happened (end of hotword * phrase). + * + * <p>Only value between 0 and 3600000 (inclusive) is accepted. */ private int mHotwordOffsetMillis = HOTWORD_OFFSET_UNSET; @@ -118,7 +126,11 @@ public final class HotwordDetectedResult implements Parcelable { */ private int mHotwordDurationMillis = 0; - /** Audio channel containing the highest-confidence hotword signal. **/ + /** + * Audio channel containing the highest-confidence hotword signal. + * + * <p>Only value between 0 and 63 (inclusive) is accepted. + */ private int mAudioChannel = AUDIO_CHANNEL_UNSET; /** @@ -249,13 +261,13 @@ public final class HotwordDetectedResult implements Parcelable { totalBits += bitCount(CONFIDENCE_LEVEL_VERY_HIGH); } if (hotwordDetectedResult.getHotwordOffsetMillis() != HOTWORD_OFFSET_UNSET) { - totalBits += Integer.SIZE; + totalBits += bitCount(LIMIT_HOTWORD_OFFSET_MAX_VALUE); } if (hotwordDetectedResult.getHotwordDurationMillis() != 0) { totalBits += bitCount(AudioRecord.getMaxSharedAudioHistoryMillis()); } if (hotwordDetectedResult.getAudioChannel() != AUDIO_CHANNEL_UNSET) { - totalBits += Integer.SIZE; + totalBits += bitCount(LIMIT_AUDIO_CHANNEL_MAX_VALUE); } // Add one bit for HotwordDetectionPersonalized @@ -294,6 +306,14 @@ public final class HotwordDetectedResult implements Parcelable { "hotwordPhraseId"); Preconditions.checkArgumentInRange((long) mHotwordDurationMillis, 0, AudioRecord.getMaxSharedAudioHistoryMillis(), "hotwordDurationMillis"); + if (mHotwordOffsetMillis != HOTWORD_OFFSET_UNSET) { + Preconditions.checkArgumentInRange(mHotwordOffsetMillis, 0, + LIMIT_HOTWORD_OFFSET_MAX_VALUE, "hotwordOffsetMillis"); + } + if (mAudioChannel != AUDIO_CHANNEL_UNSET) { + Preconditions.checkArgumentInRange(mAudioChannel, 0, LIMIT_AUDIO_CHANNEL_MAX_VALUE, + "audioChannel"); + } if (!mExtras.isEmpty()) { Preconditions.checkArgumentInRange(getParcelableSize(mExtras), 0, getMaxBundleSize(), "extras"); @@ -351,6 +371,27 @@ public final class HotwordDetectedResult implements Parcelable { } } + /** @hide */ + @IntDef(prefix = "LIMIT_", value = { + LIMIT_HOTWORD_OFFSET_MAX_VALUE, + LIMIT_AUDIO_CHANNEL_MAX_VALUE + }) + @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) + @DataClass.Generated.Member + /* package-private */ @interface Limit {} + + /** @hide */ + @DataClass.Generated.Member + /* package-private */ static String limitToString(@Limit int value) { + switch (value) { + case LIMIT_HOTWORD_OFFSET_MAX_VALUE: + return "LIMIT_HOTWORD_OFFSET_MAX_VALUE"; + case LIMIT_AUDIO_CHANNEL_MAX_VALUE: + return "LIMIT_AUDIO_CHANNEL_MAX_VALUE"; + default: return Integer.toHexString(value); + } + } + @DataClass.Generated.Member /* package-private */ HotwordDetectedResult( @HotwordConfidenceLevelValue int confidenceLevel, @@ -392,6 +433,8 @@ public final class HotwordDetectedResult implements Parcelable { /** * Offset in milliseconds the audio stream when the trigger event happened (end of hotword * phrase). + * + * <p>Only value between 0 and 3600000 (inclusive) is accepted. */ @DataClass.Generated.Member public int getHotwordOffsetMillis() { @@ -410,7 +453,9 @@ public final class HotwordDetectedResult implements Parcelable { } /** - * Audio channel containing the highest-confidence hotword signal. * + * Audio channel containing the highest-confidence hotword signal. + * + * <p>Only value between 0 and 63 (inclusive) is accepted. */ @DataClass.Generated.Member public int getAudioChannel() { @@ -667,6 +712,8 @@ public final class HotwordDetectedResult implements Parcelable { /** * Offset in milliseconds the audio stream when the trigger event happened (end of hotword * phrase). + * + * <p>Only value between 0 and 3600000 (inclusive) is accepted. */ @DataClass.Generated.Member public @NonNull Builder setHotwordOffsetMillis(int value) { @@ -691,7 +738,9 @@ public final class HotwordDetectedResult implements Parcelable { } /** - * Audio channel containing the highest-confidence hotword signal. * + * Audio channel containing the highest-confidence hotword signal. + * + * <p>Only value between 0 and 63 (inclusive) is accepted. */ @DataClass.Generated.Member public @NonNull Builder setAudioChannel(int value) { @@ -833,10 +882,10 @@ public final class HotwordDetectedResult implements Parcelable { } @DataClass.Generated( - time = 1625198973370L, + time = 1625541522353L, codegenVersion = "1.0.23", sourceFile = "frameworks/base/core/java/android/service/voice/HotwordDetectedResult.java", - inputSignatures = "public static final int CONFIDENCE_LEVEL_NONE\npublic static final int CONFIDENCE_LEVEL_LOW\npublic static final int CONFIDENCE_LEVEL_LOW_MEDIUM\npublic static final int CONFIDENCE_LEVEL_MEDIUM\npublic static final int CONFIDENCE_LEVEL_MEDIUM_HIGH\npublic static final int CONFIDENCE_LEVEL_HIGH\npublic static final int CONFIDENCE_LEVEL_VERY_HIGH\npublic static final int HOTWORD_OFFSET_UNSET\npublic static final int AUDIO_CHANNEL_UNSET\nprivate final @android.service.voice.HotwordDetectedResult.HotwordConfidenceLevelValue int mConfidenceLevel\nprivate @android.annotation.Nullable android.media.MediaSyncEvent mMediaSyncEvent\nprivate int mHotwordOffsetMillis\nprivate int mHotwordDurationMillis\nprivate int mAudioChannel\nprivate boolean mHotwordDetectionPersonalized\nprivate final int mScore\nprivate final int mPersonalizedScore\nprivate final int mHotwordPhraseId\nprivate final @android.annotation.NonNull android.os.PersistableBundle mExtras\nprivate static int sMaxBundleSize\nprivate static int defaultConfidenceLevel()\nprivate static int defaultScore()\nprivate static int defaultPersonalizedScore()\npublic static int getMaxScore()\nprivate static int defaultHotwordPhraseId()\npublic static int getMaxHotwordPhraseId()\nprivate static android.os.PersistableBundle defaultExtras()\npublic static int getMaxBundleSize()\npublic @android.annotation.Nullable android.media.MediaSyncEvent getMediaSyncEvent()\npublic static int getParcelableSize(android.os.Parcelable)\npublic static int getUsageSize(android.service.voice.HotwordDetectedResult)\nprivate static int bitCount(long)\nprivate void onConstructed()\nclass HotwordDetectedResult extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=true, genEqualsHashCode=true, genHiddenConstDefs=true, genParcelable=true, genToString=true)") + inputSignatures = "public static final int CONFIDENCE_LEVEL_NONE\npublic static final int CONFIDENCE_LEVEL_LOW\npublic static final int CONFIDENCE_LEVEL_LOW_MEDIUM\npublic static final int CONFIDENCE_LEVEL_MEDIUM\npublic static final int CONFIDENCE_LEVEL_MEDIUM_HIGH\npublic static final int CONFIDENCE_LEVEL_HIGH\npublic static final int CONFIDENCE_LEVEL_VERY_HIGH\npublic static final int HOTWORD_OFFSET_UNSET\npublic static final int AUDIO_CHANNEL_UNSET\nprivate static final int LIMIT_HOTWORD_OFFSET_MAX_VALUE\nprivate static final int LIMIT_AUDIO_CHANNEL_MAX_VALUE\nprivate final @android.service.voice.HotwordDetectedResult.HotwordConfidenceLevelValue int mConfidenceLevel\nprivate @android.annotation.Nullable android.media.MediaSyncEvent mMediaSyncEvent\nprivate int mHotwordOffsetMillis\nprivate int mHotwordDurationMillis\nprivate int mAudioChannel\nprivate boolean mHotwordDetectionPersonalized\nprivate final int mScore\nprivate final int mPersonalizedScore\nprivate final int mHotwordPhraseId\nprivate final @android.annotation.NonNull android.os.PersistableBundle mExtras\nprivate static int sMaxBundleSize\nprivate static int defaultConfidenceLevel()\nprivate static int defaultScore()\nprivate static int defaultPersonalizedScore()\npublic static int getMaxScore()\nprivate static int defaultHotwordPhraseId()\npublic static int getMaxHotwordPhraseId()\nprivate static android.os.PersistableBundle defaultExtras()\npublic static int getMaxBundleSize()\npublic @android.annotation.Nullable android.media.MediaSyncEvent getMediaSyncEvent()\npublic static int getParcelableSize(android.os.Parcelable)\npublic static int getUsageSize(android.service.voice.HotwordDetectedResult)\nprivate static int bitCount(long)\nprivate void onConstructed()\nclass HotwordDetectedResult extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=true, genEqualsHashCode=true, genHiddenConstDefs=true, genParcelable=true, genToString=true)") @Deprecated private void __metadata() {} diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java index ad09a48cf4c3..725e20f2a74d 100644 --- a/core/java/android/service/voice/VoiceInteractionSession.java +++ b/core/java/android/service/voice/VoiceInteractionSession.java @@ -2014,7 +2014,7 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall return mIndex; } - /**s + /** * @return the total number of activities for which the assist data is * being returned. */ diff --git a/core/java/android/speech/SpeechRecognizer.java b/core/java/android/speech/SpeechRecognizer.java index 94da93e9a2cf..3cdd8b8d8436 100644 --- a/core/java/android/speech/SpeechRecognizer.java +++ b/core/java/android/speech/SpeechRecognizer.java @@ -260,23 +260,7 @@ public class SpeechRecognizer { ComponentName componentName = ComponentName.unflattenFromString( context.getString(R.string.config_defaultOnDeviceSpeechRecognitionService)); - if (componentName == null) { - return false; - } - - List<ResolveInfo> resolveInfos = - context.getPackageManager().queryIntentServices( - new Intent(RecognitionService.SERVICE_INTERFACE), 0); - if (resolveInfos == null) { - return false; - } - - for (ResolveInfo ri : resolveInfos) { - if (ri.serviceInfo != null && componentName.equals(ri.serviceInfo.getComponentName())) { - return true; - } - } - return false; + return componentName != null; } /** @@ -354,20 +338,41 @@ public class SpeechRecognizer { * notifications will be received. * * @param context in which to create {@code SpeechRecognizer} - * @throws UnsupportedOperationException iff {@link #isOnDeviceRecognitionAvailable(Context)} - * is false * @return a new on-device {@code SpeechRecognizer}. + * @throws UnsupportedOperationException iff {@link #isOnDeviceRecognitionAvailable(Context)} + * is false */ @NonNull @MainThread public static SpeechRecognizer createOnDeviceSpeechRecognizer(@NonNull final Context context) { + if (!isOnDeviceRecognitionAvailable(context)) { + throw new UnsupportedOperationException("On-device recognition is not available"); + } + return lenientlyCreateOnDeviceSpeechRecognizer(context); + } + + /** + * Helper method to create on-device SpeechRecognizer in tests even when the device does not + * support on-device speech recognition. + * + * @hide + */ + @TestApi + @NonNull + @MainThread + public static SpeechRecognizer createOnDeviceTestingSpeechRecognizer( + @NonNull final Context context) { + return lenientlyCreateOnDeviceSpeechRecognizer(context); + } + + @NonNull + @MainThread + private static SpeechRecognizer lenientlyCreateOnDeviceSpeechRecognizer( + @NonNull final Context context) { if (context == null) { throw new IllegalArgumentException("Context cannot be null"); } checkIsCalledFromMainThread(); - if (!isOnDeviceRecognitionAvailable(context)) { - throw new UnsupportedOperationException("On-device recognition is not available"); - } return new SpeechRecognizer(context, /* onDevice */ true); } diff --git a/core/java/android/util/apk/ApkSignatureVerifier.java b/core/java/android/util/apk/ApkSignatureVerifier.java index 696271c69717..73f7543ba819 100644 --- a/core/java/android/util/apk/ApkSignatureVerifier.java +++ b/core/java/android/util/apk/ApkSignatureVerifier.java @@ -198,6 +198,7 @@ public class ApkSignatureVerifier { ApkSignatureSchemeV4Verifier.extractCertificates(apkPath); Certificate[][] signerCerts = new Certificate[][]{vSigner.certs}; Signature[] signerSigs = convertToSignatures(signerCerts); + Signature[] pastSignerSigs = null; if (verifyFull) { Map<Integer, byte[]> nonstreamingDigests; @@ -210,6 +211,15 @@ public class ApkSignatureVerifier { ApkSignatureSchemeV3Verifier.unsafeGetCertsWithoutVerification(apkPath); nonstreamingDigests = v3Signer.contentDigests; nonstreamingCerts = new Certificate[][]{v3Signer.certs}; + if (v3Signer.por != null) { + // populate proof-of-rotation information + pastSignerSigs = new Signature[v3Signer.por.certs.size()]; + for (int i = 0; i < pastSignerSigs.length; i++) { + pastSignerSigs[i] = new Signature( + v3Signer.por.certs.get(i).getEncoded()); + pastSignerSigs[i].setFlags(v3Signer.por.flagsList.get(i)); + } + } } catch (SignatureNotFoundException e) { try { ApkSignatureSchemeV2Verifier.VerifiedSigner v2Signer = @@ -250,7 +260,8 @@ public class ApkSignatureVerifier { } return new SigningDetailsWithDigests(new PackageParser.SigningDetails(signerSigs, - SignatureSchemeVersion.SIGNING_BLOCK_V4), vSigner.contentDigests); + SignatureSchemeVersion.SIGNING_BLOCK_V4, pastSignerSigs), + vSigner.contentDigests); } catch (SignatureNotFoundException e) { throw e; } catch (Exception e) { diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 305cb97dbc77..f4539c2f8859 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -814,9 +814,10 @@ interface IWindowManager * @param displayId The display associated with the window context * @param options A bundle used to pass window-related options and choose the right DisplayArea * - * @return {@code true} if the WindowContext is attached to the DisplayArea successfully. + * @return the DisplayArea's {@link android.app.res.Configuration} if the WindowContext is + * attached to the DisplayArea successfully. {@code null}, otherwise. */ - boolean attachWindowContextToDisplayArea(IBinder clientToken, int type, int displayId, + Configuration attachWindowContextToDisplayArea(IBinder clientToken, int type, int displayId, in Bundle options); /** diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java index 145607ada4f4..6f915c9182d2 100644 --- a/core/java/android/view/InsetsController.java +++ b/core/java/android/view/InsetsController.java @@ -128,6 +128,10 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation */ @Appearance int getSystemBarsAppearance(); + default boolean isSystemBarsAppearanceControlled() { + return false; + } + /** * @see WindowInsetsController#setSystemBarsBehavior */ @@ -138,6 +142,10 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation */ @Behavior int getSystemBarsBehavior(); + default boolean isSystemBarsBehaviorControlled() { + return false; + } + /** * Releases a surface and ensure that this is done after {@link #applySurfaceParams} has * finished applying params. @@ -1520,6 +1528,10 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation @Override public @Appearance int getSystemBarsAppearance() { + if (!mHost.isSystemBarsAppearanceControlled()) { + // We only return the requested appearance, not the implied one. + return 0; + } return mHost.getSystemBarsAppearance(); } @@ -1544,6 +1556,10 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation @Override public @Behavior int getSystemBarsBehavior() { + if (!mHost.isSystemBarsBehaviorControlled()) { + // We only return the requested behavior, not the implied one. + return 0; + } return mHost.getSystemBarsBehavior(); } diff --git a/core/java/android/view/RemoteAnimationAdapter.java b/core/java/android/view/RemoteAnimationAdapter.java index a78036fba094..e1cc60491f72 100644 --- a/core/java/android/view/RemoteAnimationAdapter.java +++ b/core/java/android/view/RemoteAnimationAdapter.java @@ -17,6 +17,7 @@ package android.view; import android.app.ActivityOptions; +import android.app.IApplicationThread; import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Parcel; @@ -58,6 +59,9 @@ public class RemoteAnimationAdapter implements Parcelable { private int mCallingPid; private int mCallingUid; + /** @see #getCallingApplication */ + private IApplicationThread mCallingApplication; + /** * @param runner The interface that gets notified when we actually need to start the animation. * @param duration The duration of the animation. @@ -81,11 +85,19 @@ public class RemoteAnimationAdapter implements Parcelable { this(runner, duration, statusBarTransitionDelay, false /* changeNeedsSnapshot */); } + @UnsupportedAppUsage + public RemoteAnimationAdapter(IRemoteAnimationRunner runner, long duration, + long statusBarTransitionDelay, IApplicationThread callingApplication) { + this(runner, duration, statusBarTransitionDelay, false /* changeNeedsSnapshot */); + mCallingApplication = callingApplication; + } + public RemoteAnimationAdapter(Parcel in) { mRunner = IRemoteAnimationRunner.Stub.asInterface(in.readStrongBinder()); mDuration = in.readLong(); mStatusBarTransitionDelay = in.readLong(); mChangeNeedsSnapshot = in.readBoolean(); + mCallingApplication = IApplicationThread.Stub.asInterface(in.readStrongBinder()); } public IRemoteAnimationRunner getRunner() { @@ -126,6 +138,15 @@ public class RemoteAnimationAdapter implements Parcelable { return mCallingUid; } + /** + * Gets the ApplicationThread that will run the animation. Instead it is intended to pass the + * calling information among client processes (eg. shell + launcher) through one-way binder + * calls (where binder itself doesn't track calling information). + */ + public IApplicationThread getCallingApplication() { + return mCallingApplication; + } + @Override public int describeContents() { return 0; @@ -137,6 +158,7 @@ public class RemoteAnimationAdapter implements Parcelable { dest.writeLong(mDuration); dest.writeLong(mStatusBarTransitionDelay); dest.writeBoolean(mChangeNeedsSnapshot); + dest.writeStrongInterface(mCallingApplication); } public static final @android.annotation.NonNull Creator<RemoteAnimationAdapter> CREATOR diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index 1d8eb5eeb104..b300f3031a00 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -236,6 +236,7 @@ public final class SurfaceControl implements Parcelable { private static native long nativeCreateJankDataListenerWrapper(OnJankDataListener listener); private static native int nativeGetGPUContextPriority(); private static native void nativeSetTransformHint(long nativeObject, int transformHint); + private static native int nativeGetTransformHint(long nativeObject); @Nullable @GuardedBy("mLock") @@ -619,7 +620,6 @@ public final class SurfaceControl implements Parcelable { mName = other.mName; mWidth = other.mWidth; mHeight = other.mHeight; - mTransformHint = other.mTransformHint; mLocalOwnerView = other.mLocalOwnerView; assignNativeObject(nativeCopyFromSurfaceControl(other.mNativeObject), callsite); } @@ -1482,7 +1482,6 @@ public final class SurfaceControl implements Parcelable { mName = in.readString8(); mWidth = in.readInt(); mHeight = in.readInt(); - mTransformHint = in.readInt(); long object = 0; if (in.readInt() != 0) { @@ -1501,7 +1500,6 @@ public final class SurfaceControl implements Parcelable { dest.writeString8(mName); dest.writeInt(mWidth); dest.writeInt(mHeight); - dest.writeInt(mTransformHint); if (mNativeObject == 0) { dest.writeInt(0); } else { @@ -3625,7 +3623,8 @@ public final class SurfaceControl implements Parcelable { * @hide */ public int getTransformHint() { - return mTransformHint; + checkNotReleased(); + return nativeGetTransformHint(mNativeObject); } /** @@ -3638,9 +3637,6 @@ public final class SurfaceControl implements Parcelable { * @hide */ public void setTransformHint(@Surface.Rotation int transformHint) { - if (mTransformHint != transformHint) { - mTransformHint = transformHint; - nativeSetTransformHint(mNativeObject, transformHint); - } + nativeSetTransformHint(mNativeObject, transformHint); } } diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 155bc0a429be..34c4e5df1fd5 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -253,6 +253,13 @@ public final class ViewRootImpl implements ViewParent, private static final boolean MT_RENDERER_AVAILABLE = true; /** + * Whether or not to report end-to-end input latency. Disabled temporarily as a + * risk mitigation against potential jank caused by acquiring a weak reference + * per frame + */ + private static final boolean ENABLE_INPUT_LATENCY_TRACKING = false; + + /** * Set this system property to true to force the view hierarchy to render * at 60 Hz. This can be used to measure the potential framerate. */ @@ -1222,7 +1229,7 @@ public final class ViewRootImpl implements ViewParent, mInputEventReceiver = new WindowInputEventReceiver(inputChannel, Looper.myLooper()); - if (mAttachInfo.mThreadedRenderer != null) { + if (ENABLE_INPUT_LATENCY_TRACKING && mAttachInfo.mThreadedRenderer != null) { InputMetricsListener listener = new InputMetricsListener(); mHardwareRendererObserver = new HardwareRendererObserver( listener, listener.data, mHandler, true /*waitForPresentTime*/); @@ -2786,6 +2793,7 @@ public final class ViewRootImpl implements ViewParent, mView.onSystemBarAppearanceChanged(mDispatchedSystemBarAppearance); } } + final boolean wasReportNextDraw = mReportNextDraw; if (mFirst || windowShouldResize || viewVisibilityChanged || params != null || mForceNextWindowRelayout) { @@ -2832,6 +2840,16 @@ public final class ViewRootImpl implements ViewParent, final boolean dockedResizing = (relayoutResult & WindowManagerGlobal.RELAYOUT_RES_DRAG_RESIZING_DOCKED) != 0; final boolean dragResizing = freeformResizing || dockedResizing; + if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_BLAST_SYNC) != 0) { + if (DEBUG_BLAST) { + Log.d(mTag, "Relayout called with blastSync"); + } + reportNextDraw(); + if (isHardwareEnabled()) { + mNextDrawUseBlastSync = true; + } + } + if (mSurfaceControl.isValid()) { updateOpacity(mWindowAttributes, dragResizing); } @@ -3050,7 +3068,16 @@ public final class ViewRootImpl implements ViewParent, } } - if (!mStopped || mReportNextDraw) { + // TODO: In the CL "ViewRootImpl: Fix issue with early draw report in + // seamless rotation". We moved processing of RELAYOUT_RES_BLAST_SYNC + // earlier in the function, potentially triggering a call to + // reportNextDraw(). That same CL changed this and the next reference + // to wasReportNextDraw, such that this logic would remain undisturbed + // (it continues to operate as if the code was never moved). This was + // done to achieve a more hermetic fix for S, but it's entirely + // possible that checking the most recent value is actually more + // correct here. + if (!mStopped || wasReportNextDraw) { boolean focusChangedDueToTouchMode = ensureTouchModeLocally( (relayoutResult&WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE) != 0); if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth() @@ -3120,7 +3147,7 @@ public final class ViewRootImpl implements ViewParent, prepareSurfaces(); } - final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw); + final boolean didLayout = layoutRequested && (!mStopped || wasReportNextDraw); boolean triggerGlobalLayoutListener = didLayout || mAttachInfo.mRecomputeGlobalAttributes; if (didLayout) { @@ -3276,21 +3303,10 @@ public final class ViewRootImpl implements ViewParent, mImeFocusController.onTraversal(hasWindowFocus, mWindowAttributes); - final boolean wasReportNextDraw = mReportNextDraw; - // Remember if we must report the next draw. if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) { reportNextDraw(); } - if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_BLAST_SYNC) != 0) { - if (DEBUG_BLAST) { - Log.d(mTag, "Relayout called with blastSync"); - } - reportNextDraw(); - if (isHardwareEnabled()) { - mNextDrawUseBlastSync = true; - } - } boolean cancelDraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw() || !isViewVisible; @@ -3301,7 +3317,6 @@ public final class ViewRootImpl implements ViewParent, } mPendingTransitions.clear(); } - performDraw(); } else { if (isViewVisible) { diff --git a/core/java/android/view/ViewRootInsetsControllerHost.java b/core/java/android/view/ViewRootInsetsControllerHost.java index 27821fd6608d..ce882da1a6da 100644 --- a/core/java/android/view/ViewRootInsetsControllerHost.java +++ b/core/java/android/view/ViewRootInsetsControllerHost.java @@ -180,14 +180,15 @@ public class ViewRootInsetsControllerHost implements InsetsController.Host { @Override public int getSystemBarsAppearance() { - if ((mViewRoot.mWindowAttributes.privateFlags & PRIVATE_FLAG_APPEARANCE_CONTROLLED) == 0) { - // We only return the requested appearance, not the implied one. - return 0; - } return mViewRoot.mWindowAttributes.insetsFlags.appearance; } @Override + public boolean isSystemBarsAppearanceControlled() { + return (mViewRoot.mWindowAttributes.privateFlags & PRIVATE_FLAG_APPEARANCE_CONTROLLED) != 0; + } + + @Override public void setSystemBarsBehavior(int behavior) { mViewRoot.mWindowAttributes.privateFlags |= PRIVATE_FLAG_BEHAVIOR_CONTROLLED; if (mViewRoot.mWindowAttributes.insetsFlags.behavior != behavior) { @@ -199,14 +200,15 @@ public class ViewRootInsetsControllerHost implements InsetsController.Host { @Override public int getSystemBarsBehavior() { - if ((mViewRoot.mWindowAttributes.privateFlags & PRIVATE_FLAG_BEHAVIOR_CONTROLLED) == 0) { - // We only return the requested behavior, not the implied one. - return 0; - } return mViewRoot.mWindowAttributes.insetsFlags.behavior; } @Override + public boolean isSystemBarsBehaviorControlled() { + return (mViewRoot.mWindowAttributes.privateFlags & PRIVATE_FLAG_BEHAVIOR_CONTROLLED) != 0; + } + + @Override public void releaseSurfaceControlFromRt(SurfaceControl surfaceControl) { // At the time we receive new leashes (e.g. InsetsSourceConsumer is processing diff --git a/core/java/android/widget/AnalogClock.java b/core/java/android/widget/AnalogClock.java index 9c1285064afb..3df09c24ca30 100644 --- a/core/java/android/widget/AnalogClock.java +++ b/core/java/android/widget/AnalogClock.java @@ -740,8 +740,22 @@ public class AnalogClock extends View { } } - private void onTimeChanged() { - Instant now = mClock.instant(); + /** + * Return the current Instant to be used for drawing the clockface. Protected to allow + * subclasses to override this to show a different time from the system clock. + * + * @return the Instant to be shown on the clockface + * @hide + */ + protected Instant now() { + return mClock.instant(); + } + + /** + * @hide + */ + protected void onTimeChanged() { + Instant now = now(); onTimeChanged(now.atZone(mClock.getZone()).toLocalTime(), now.toEpochMilli()); } @@ -789,7 +803,7 @@ public class AnalogClock extends View { return; } - Instant now = mClock.instant(); + Instant now = now(); ZonedDateTime zonedDateTime = now.atZone(mClock.getZone()); LocalTime localTime = zonedDateTime.toLocalTime(); diff --git a/core/java/android/window/ITaskFragmentOrganizer.aidl b/core/java/android/window/ITaskFragmentOrganizer.aidl index 0bfc2541061c..5eb432e785ee 100644 --- a/core/java/android/window/ITaskFragmentOrganizer.aidl +++ b/core/java/android/window/ITaskFragmentOrganizer.aidl @@ -17,6 +17,7 @@ package android.window; import android.content.res.Configuration; +import android.os.Bundle; import android.os.IBinder; import android.window.TaskFragmentAppearedInfo; import android.window.TaskFragmentInfo; @@ -37,4 +38,15 @@ oneway interface ITaskFragmentOrganizer { * bounds. */ void onTaskFragmentParentInfoChanged(in IBinder fragmentToken, in Configuration parentConfig); + + /** + * Called when the {@link WindowContainerTransaction} created with + * {@link WindowContainerTransaction#setErrorCallbackToken(IBinder)} failed on the server side. + * + * @param errorCallbackToken Token set through {@link + * WindowContainerTransaction#setErrorCallbackToken(IBinder)} + * @param exceptionBundle Bundle containing the exception. Should be created with + * {@link TaskFragmentOrganizer#putExceptionInBundle}. + */ + void onTaskFragmentError(in IBinder errorCallbackToken, in Bundle exceptionBundle); } diff --git a/core/java/android/window/ITaskOrganizerController.aidl b/core/java/android/window/ITaskOrganizerController.aidl index 2d0211e129bf..a833600e1fbc 100644 --- a/core/java/android/window/ITaskOrganizerController.aidl +++ b/core/java/android/window/ITaskOrganizerController.aidl @@ -61,4 +61,9 @@ interface ITaskOrganizerController { */ void setInterceptBackPressedOnTaskRoot(in WindowContainerToken task, boolean interceptBackPressed); + + /** + * Restarts the top activity in the given task by killing its process if it is visible. + */ + void restartTaskTopActivityProcessIfVisible(in WindowContainerToken task); } diff --git a/core/java/android/window/TaskFragmentInfo.java b/core/java/android/window/TaskFragmentInfo.java index e032153bc013..6d4a2f130129 100644 --- a/core/java/android/window/TaskFragmentInfo.java +++ b/core/java/android/window/TaskFragmentInfo.java @@ -20,12 +20,14 @@ import static android.app.WindowConfiguration.WindowingMode; import android.annotation.NonNull; import android.annotation.Nullable; -import android.content.ComponentName; import android.content.res.Configuration; import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; +import java.util.ArrayList; +import java.util.List; + /** * Stores information about a particular TaskFragment. * @hide @@ -39,13 +41,6 @@ public final class TaskFragmentInfo implements Parcelable { @NonNull private final IBinder mFragmentToken; - /** - * The component name of the initial root activity of this TaskFragment, which will be used - * to configure the relationships for TaskFragments. - */ - @NonNull - private final ComponentName mInitialComponentName; - @NonNull private final WindowContainerToken mToken; @@ -58,29 +53,31 @@ public final class TaskFragmentInfo implements Parcelable { /** Whether this TaskFragment is visible on the window hierarchy. */ private final boolean mIsVisible; + /** + * List of Activity tokens that are children of this TaskFragment. It only contains Activities + * that belong to the organizer process for security. + */ + private final List<IBinder> mActivities = new ArrayList<>(); + public TaskFragmentInfo( - @NonNull IBinder fragmentToken, @NonNull ComponentName initialComponentName, - @NonNull WindowContainerToken token, @NonNull Configuration configuration, - boolean isEmpty, boolean isVisible) { - if (fragmentToken == null || initialComponentName == null) { + @NonNull IBinder fragmentToken, @NonNull WindowContainerToken token, + @NonNull Configuration configuration, boolean isEmpty, boolean isVisible, + List<IBinder> activities) { + if (fragmentToken == null) { throw new IllegalArgumentException("Invalid TaskFragmentInfo."); } mFragmentToken = fragmentToken; - mInitialComponentName = initialComponentName; mToken = token; mConfiguration.setTo(configuration); mIsEmpty = isEmpty; mIsVisible = isVisible; + mActivities.addAll(activities); } public IBinder getFragmentToken() { return mFragmentToken; } - public ComponentName getInitialComponentName() { - return mInitialComponentName; - } - public WindowContainerToken getToken() { return mToken; } @@ -97,6 +94,10 @@ public final class TaskFragmentInfo implements Parcelable { return mIsVisible; } + public List<IBinder> getActivities() { + return mActivities; + } + @WindowingMode public int getWindowingMode() { return mConfiguration.windowConfiguration.getWindowingMode(); @@ -112,30 +113,30 @@ public final class TaskFragmentInfo implements Parcelable { } return mFragmentToken.equals(that.mFragmentToken) - && mInitialComponentName.equals(that.mInitialComponentName) && mToken.equals(that.mToken) && mIsEmpty == that.mIsEmpty && mIsVisible == that.mIsVisible - && getWindowingMode() == that.getWindowingMode(); + && getWindowingMode() == that.getWindowingMode() + && mActivities.equals(that.mActivities); } private TaskFragmentInfo(Parcel in) { mFragmentToken = in.readStrongBinder(); - mInitialComponentName = in.readTypedObject(ComponentName.CREATOR); mToken = in.readTypedObject(WindowContainerToken.CREATOR); mConfiguration.readFromParcel(in); mIsEmpty = in.readBoolean(); mIsVisible = in.readBoolean(); + in.readBinderList(mActivities); } @Override public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeStrongBinder(mFragmentToken); - dest.writeTypedObject(mInitialComponentName, flags); dest.writeTypedObject(mToken, flags); mConfiguration.writeToParcel(dest, flags); dest.writeBoolean(mIsEmpty); dest.writeBoolean(mIsVisible); + dest.writeBinderList(mActivities); } @NonNull @@ -156,7 +157,6 @@ public final class TaskFragmentInfo implements Parcelable { public String toString() { return "TaskFragmentInfo{" + " fragmentToken=" + mFragmentToken - + " initialComponentName=" + mInitialComponentName + " token=" + mToken + " isEmpty=" + mIsEmpty + " isVisible=" + mIsVisible diff --git a/core/java/android/window/TaskFragmentOrganizer.java b/core/java/android/window/TaskFragmentOrganizer.java index 51722cccb44d..3b4d4e52c908 100644 --- a/core/java/android/window/TaskFragmentOrganizer.java +++ b/core/java/android/window/TaskFragmentOrganizer.java @@ -19,6 +19,7 @@ package android.window; import android.annotation.CallSuper; import android.annotation.NonNull; import android.content.res.Configuration; +import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; @@ -31,6 +32,21 @@ import java.util.concurrent.Executor; public class TaskFragmentOrganizer extends WindowOrganizer { /** + * Key to the exception in {@link Bundle} in {@link ITaskFragmentOrganizer#onTaskFragmentError}. + */ + private static final String KEY_ERROR_CALLBACK_EXCEPTION = "fragment_exception"; + + /** + * Creates a {@link Bundle} with an exception that can be passed to + * {@link ITaskFragmentOrganizer#onTaskFragmentError}. + */ + public static Bundle putExceptionInBundle(@NonNull Throwable exception) { + final Bundle exceptionBundle = new Bundle(); + exceptionBundle.putSerializable(KEY_ERROR_CALLBACK_EXCEPTION, exception); + return exceptionBundle; + } + + /** * Callbacks from WM Core are posted on this executor. */ private final Executor mExecutor; @@ -93,6 +109,17 @@ public class TaskFragmentOrganizer extends WindowOrganizer { public void onTaskFragmentParentInfoChanged( @NonNull IBinder fragmentToken, @NonNull Configuration parentConfig) {} + /** + * Called when the {@link WindowContainerTransaction} created with + * {@link WindowContainerTransaction#setErrorCallbackToken(IBinder)} failed on the server side. + * + * @param errorCallbackToken token set in + * {@link WindowContainerTransaction#setErrorCallbackToken(IBinder)} + * @param exception exception from the server side. + */ + public void onTaskFragmentError( + @NonNull IBinder errorCallbackToken, @NonNull Throwable exception) {} + private final ITaskFragmentOrganizer mInterface = new ITaskFragmentOrganizer.Stub() { @Override public void onTaskFragmentAppeared(@NonNull TaskFragmentAppearedInfo taskFragmentInfo) { @@ -119,8 +146,20 @@ public class TaskFragmentOrganizer extends WindowOrganizer { () -> TaskFragmentOrganizer.this.onTaskFragmentParentInfoChanged( fragmentToken, parentConfig)); } + + @Override + public void onTaskFragmentError( + @NonNull IBinder errorCallbackToken, @NonNull Bundle exceptionBundle) { + mExecutor.execute(() -> TaskFragmentOrganizer.this.onTaskFragmentError( + errorCallbackToken, + (Throwable) exceptionBundle.getSerializable(KEY_ERROR_CALLBACK_EXCEPTION))); + } }; + public ITaskFragmentOrganizer getIOrganizer() { + return mInterface; + } + private ITaskFragmentOrganizerController getController() { try { return getWindowOrganizerController().getTaskFragmentOrganizerController(); diff --git a/core/java/android/window/TaskOrganizer.java b/core/java/android/window/TaskOrganizer.java index 73995491668a..8fa011028f44 100644 --- a/core/java/android/window/TaskOrganizer.java +++ b/core/java/android/window/TaskOrganizer.java @@ -222,6 +222,20 @@ public class TaskOrganizer extends WindowOrganizer { } } + + /** + * Restarts the top activity in the given task by killing its process if it is visible. + * @hide + */ + @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) + public void restartTaskTopActivityProcessIfVisible(@NonNull WindowContainerToken task) { + try { + mTaskOrganizerController.restartTaskTopActivityProcessIfVisible(task); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + /** * Gets the executor to run callbacks on. * @hide diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java index 8c3dc2e2044e..9c512add3345 100644 --- a/core/java/android/window/WindowContainerTransaction.java +++ b/core/java/android/window/WindowContainerTransaction.java @@ -49,11 +49,15 @@ public final class WindowContainerTransaction implements Parcelable { // Flat list because re-order operations are order-dependent private final ArrayList<HierarchyOp> mHierarchyOps = new ArrayList<>(); + @Nullable + private IBinder mErrorCallbackToken; + public WindowContainerTransaction() {} private WindowContainerTransaction(Parcel in) { in.readMap(mChanges, null /* loader */); in.readList(mHierarchyOps, null /* loader */); + mErrorCallbackToken = in.readStrongBinder(); } private Change getOrCreateChange(IBinder token) { @@ -476,6 +480,23 @@ public final class WindowContainerTransaction implements Parcelable { } /** + * When this {@link WindowContainerTransaction} failed to finish on the server side, it will + * trigger callback with this {@param errorCallbackToken}. + * @param errorCallbackToken client provided token that will be passed back as parameter in + * the callback if there is an error on the server side. + * @see ITaskFragmentOrganizer#onTaskFragmentError + * @hide + */ + @NonNull + public WindowContainerTransaction setErrorCallbackToken(@NonNull IBinder errorCallbackToken) { + if (mErrorCallbackToken != null) { + throw new IllegalStateException("Can't set multiple error token for one transaction."); + } + mErrorCallbackToken = errorCallbackToken; + return this; + } + + /** * Merges another WCT into this one. * @param transfer When true, this will transfer everything from other potentially leaving * other in an unusable state. When false, other is left alone, but @@ -496,6 +517,13 @@ public final class WindowContainerTransaction implements Parcelable { mHierarchyOps.add(transfer ? other.mHierarchyOps.get(i) : new HierarchyOp(other.mHierarchyOps.get(i))); } + if (mErrorCallbackToken != null && other.mErrorCallbackToken != null && mErrorCallbackToken + != other.mErrorCallbackToken) { + throw new IllegalArgumentException("Can't merge two WCT with different error token"); + } + mErrorCallbackToken = mErrorCallbackToken != null + ? mErrorCallbackToken + : other.mErrorCallbackToken; } /** @hide */ @@ -513,11 +541,17 @@ public final class WindowContainerTransaction implements Parcelable { return mHierarchyOps; } + /** @hide */ + @Nullable + public IBinder getErrorCallbackToken() { + return mErrorCallbackToken; + } + @Override @NonNull public String toString() { return "WindowContainerTransaction { changes = " + mChanges + " hops = " + mHierarchyOps - + " }"; + + " errorCallbackToken=" + mErrorCallbackToken + " }"; } @Override @@ -525,6 +559,7 @@ public final class WindowContainerTransaction implements Parcelable { public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeMap(mChanges); dest.writeList(mHierarchyOps); + dest.writeStrongBinder(mErrorCallbackToken); } @Override diff --git a/core/java/android/window/WindowContext.java b/core/java/android/window/WindowContext.java index 69d7b4c7d696..5d400853540f 100644 --- a/core/java/android/window/WindowContext.java +++ b/core/java/android/window/WindowContext.java @@ -26,7 +26,6 @@ import android.content.Context; import android.content.ContextWrapper; import android.content.res.Configuration; import android.os.Bundle; -import android.os.IBinder; import android.view.WindowManager; import com.android.internal.annotations.VisibleForTesting; @@ -73,7 +72,7 @@ public class WindowContext extends ContextWrapper { mType = type; mOptions = options; mWindowManager = createWindowContextWindowManager(this); - IBinder token = getWindowContextToken(); + WindowTokenClient token = (WindowTokenClient) getWindowContextToken(); mController = new WindowContextController(token); Reference.reachabilityFence(this); diff --git a/core/java/android/window/WindowContextController.java b/core/java/android/window/WindowContextController.java index d84f571931fd..5aa623388574 100644 --- a/core/java/android/window/WindowContextController.java +++ b/core/java/android/window/WindowContextController.java @@ -19,6 +19,7 @@ package android.window; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; +import android.content.res.Configuration; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; @@ -46,7 +47,7 @@ public class WindowContextController { @VisibleForTesting public boolean mAttachedToDisplayArea; @NonNull - private final IBinder mToken; + private final WindowTokenClient mToken; /** * Window Context Controller constructor @@ -54,14 +55,13 @@ public class WindowContextController { * @param token The token used to attach to a window manager node. It is usually from * {@link Context#getWindowContextToken()}. */ - public WindowContextController(@NonNull IBinder token) { - mToken = token; - mWms = WindowManagerGlobal.getWindowManagerService(); + public WindowContextController(@NonNull WindowTokenClient token) { + this(token, WindowManagerGlobal.getWindowManagerService()); } /** Used for test only. DO NOT USE it in production code. */ @VisibleForTesting - public WindowContextController(@NonNull IBinder token, IWindowManager mockWms) { + public WindowContextController(@NonNull WindowTokenClient token, IWindowManager mockWms) { mToken = token; mWms = mockWms; } @@ -81,8 +81,15 @@ public class WindowContextController { + "a DisplayArea once."); } try { - mAttachedToDisplayArea = mWms.attachWindowContextToDisplayArea(mToken, type, displayId, - options); + final Configuration configuration = mWms.attachWindowContextToDisplayArea(mToken, type, + displayId, options); + if (configuration != null) { + mAttachedToDisplayArea = true; + // Send the DisplayArea's configuration to WindowContext directly instead of + // waiting for dispatching from WMS. + mToken.onConfigurationChanged(configuration, displayId, + false /* shouldReportConfigChange */); + } } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/window/WindowTokenClient.java b/core/java/android/window/WindowTokenClient.java index c32a268cef5c..284b4b98b4c9 100644 --- a/core/java/android/window/WindowTokenClient.java +++ b/core/java/android/window/WindowTokenClient.java @@ -29,9 +29,12 @@ import android.content.res.Configuration; import android.inputmethodservice.AbstractInputMethodService; import android.os.Build; import android.os.Bundle; +import android.os.Debug; import android.os.IBinder; import android.util.Log; +import com.android.internal.annotations.VisibleForTesting; + import java.lang.ref.WeakReference; /** @@ -65,7 +68,7 @@ public class WindowTokenClient extends IWindowToken.Stub { * can only attach one {@link Context}. * <p>This method must be called before invoking * {@link android.view.IWindowManager#attachWindowContextToDisplayArea(IBinder, int, int, - * Bundle, boolean)}.<p/> + * Bundle)}.<p/> * * @param context context to be attached * @throws IllegalStateException if attached context has already existed. @@ -80,8 +83,26 @@ public class WindowTokenClient extends IWindowToken.Stub { && context instanceof AbstractInputMethodService; } + /** + * Called when {@link Configuration} updates from the server side receive. + * + * @param newConfig the updated {@link Configuration} + * @param newDisplayId the updated {@link android.view.Display} ID + */ @Override public void onConfigurationChanged(Configuration newConfig, int newDisplayId) { + onConfigurationChanged(newConfig, newDisplayId, true /* shouldReportConfigChange */); + } + + /** + * Called when {@link Configuration} updates from the server side receive. + * + * Similar to {@link #onConfigurationChanged(Configuration, int)}, but adds a flag to control + * whether to dispatch configuration update or not. + */ + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) + public void onConfigurationChanged(Configuration newConfig, int newDisplayId, + boolean shouldReportConfigChange) { final Context context = mContextRef.get(); if (context == null) { return; @@ -102,9 +123,10 @@ public class WindowTokenClient extends IWindowToken.Stub { // TODO(ag/9789103): update resource manager logic to track non-activity tokens mResourcesManager.updateResourcesForActivity(this, newConfig, newDisplayId); - if (context instanceof WindowContext) { + if (shouldReportConfigChange && context instanceof WindowContext) { + final WindowContext windowContext = (WindowContext) context; ActivityThread.currentActivityThread().getHandler().post( - () -> ((WindowContext) context).dispatchConfigurationChanged(newConfig)); + () -> windowContext.dispatchConfigurationChanged(newConfig)); } // Dispatch onConfigurationChanged only if there's a significant public change to @@ -115,17 +137,24 @@ public class WindowTokenClient extends IWindowToken.Stub { ? new SizeConfigurationBuckets(sizeConfigurations) : null; final int diff = diffPublicWithSizeBuckets(mConfiguration, newConfig, buckets); - if (context instanceof WindowProviderService && diff != 0) { - ActivityThread.currentActivityThread().getHandler().post(() -> - ((WindowProviderService) context).onConfigurationChanged(newConfig)); + if (shouldReportConfigChange && diff != 0 + && context instanceof WindowProviderService) { + final WindowProviderService windowProviderService = (WindowProviderService) context; + ActivityThread.currentActivityThread().getHandler().post( + () -> windowProviderService.onConfigurationChanged(newConfig)); } freeTextLayoutCachesIfNeeded(diff); - if (diff == 0 && mShouldDumpConfigForIme) { - Log.d(TAG, "Configuration not dispatch to IME because configuration has no " - + " public difference with updated config. " - + " Current config=" + context.getResources().getConfiguration() - + ", reported config=" + mConfiguration - + ", updated config=" + newConfig); + if (mShouldDumpConfigForIme) { + if (!shouldReportConfigChange) { + Log.d(TAG, "Only apply configuration update to Resources because " + + "shouldReportConfigChange is false.\n" + Debug.getCallers(5)); + } else if (diff == 0) { + Log.d(TAG, "Configuration not dispatch to IME because configuration has no " + + " public difference with updated config. " + + " Current config=" + context.getResources().getConfiguration() + + ", reported config=" + mConfiguration + + ", updated config=" + newConfig); + } } mConfiguration.setTo(newConfig); } diff --git a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl index dddc08a88062..c8a4425409e8 100644 --- a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl +++ b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl @@ -231,6 +231,9 @@ interface IVoiceInteractionManagerService { /** * Set configuration and pass read-only data to hotword detection service. + * Caller must provide an identity, used for permission tracking purposes. + * The uid/pid elements of the identity will be ignored by the server and replaced with the ones + * provided by binder. * * @param options Application configuration data to provide to the * {@link HotwordDetectionService}. PersistableBundle does not allow any remotable objects or @@ -241,6 +244,7 @@ interface IVoiceInteractionManagerService { * @param callback Use this to report {@link HotwordDetectionService} status. */ void updateState( + in Identity originatorIdentity, in PersistableBundle options, in SharedMemory sharedMemory, in IHotwordRecognitionStatusCallback callback); diff --git a/core/java/com/android/internal/app/PlatLogoActivity.java b/core/java/com/android/internal/app/PlatLogoActivity.java index 986bbc8628ec..b7f6a615a452 100644 --- a/core/java/com/android/internal/app/PlatLogoActivity.java +++ b/core/java/com/android/internal/app/PlatLogoActivity.java @@ -16,9 +16,9 @@ package com.android.internal.app; +import static android.graphics.PixelFormat.TRANSLUCENT; + import android.animation.ObjectAnimator; -import android.annotation.NonNull; -import android.annotation.Nullable; import android.app.ActionBar; import android.app.Activity; import android.content.ActivityNotFoundException; @@ -26,22 +26,21 @@ import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.graphics.Canvas; -import android.graphics.Color; import android.graphics.ColorFilter; -import android.graphics.LinearGradient; import android.graphics.Paint; -import android.graphics.PixelFormat; import android.graphics.Rect; -import android.graphics.Shader; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.provider.Settings; -import android.util.AttributeSet; +import android.util.DisplayMetrics; import android.util.Log; +import android.view.Gravity; import android.view.HapticFeedbackConstants; import android.view.MotionEvent; import android.view.View; -import android.view.animation.PathInterpolator; +import android.view.animation.DecelerateInterpolator; +import android.view.animation.OvershootInterpolator; +import android.widget.AnalogClock; import android.widget.FrameLayout; import android.widget.ImageView; @@ -49,17 +48,22 @@ import com.android.internal.R; import org.json.JSONObject; +import java.time.Clock; +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZonedDateTime; + /** * @hide */ public class PlatLogoActivity extends Activity { - private static final boolean WRITE_SETTINGS = true; - - private static final String R_EGG_UNLOCK_SETTING = "egg_mode_r"; + private static final String TAG = "PlatLogoActivity"; - private static final int UNLOCK_TRIES = 3; + private static final String S_EGG_UNLOCK_SETTING = "egg_mode_s"; - BigDialView mDialView; + private SettableAnalogClock mClock; + private ImageView mLogo; + private BubblesDrawable mBg; @Override protected void onPause() { @@ -69,42 +73,81 @@ public class PlatLogoActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - final float dp = getResources().getDisplayMetrics().density; - getWindow().getDecorView().setSystemUiVisibility( - View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE); getWindow().setNavigationBarColor(0); getWindow().setStatusBarColor(0); final ActionBar ab = getActionBar(); if (ab != null) ab.hide(); - mDialView = new BigDialView(this, null); - if (Settings.System.getLong(getContentResolver(), - R_EGG_UNLOCK_SETTING, 0) == 0) { - mDialView.setUnlockTries(UNLOCK_TRIES); - } else { - mDialView.setUnlockTries(0); - } - final FrameLayout layout = new FrameLayout(this); - layout.setBackgroundColor(0xFFFF0000); - layout.addView(mDialView, FrameLayout.LayoutParams.MATCH_PARENT, - FrameLayout.LayoutParams.MATCH_PARENT); + + mClock = new SettableAnalogClock(this); + + final DisplayMetrics dm = getResources().getDisplayMetrics(); + final float dp = dm.density; + final int minSide = Math.min(dm.widthPixels, dm.heightPixels); + final int widgetSize = (int) (minSide * 0.75); + final FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(widgetSize, widgetSize); + lp.gravity = Gravity.CENTER; + layout.addView(mClock, lp); + + mLogo = new ImageView(this); + mLogo.setVisibility(View.GONE); + mLogo.setImageResource(R.drawable.platlogo); + layout.addView(mLogo, lp); + + mBg = new BubblesDrawable(); + mBg.setLevel(0); + mBg.avoid = widgetSize / 2; + mBg.padding = 0.5f * dp; + mBg.minR = 1 * dp; + layout.setBackground(mBg); + setContentView(layout); } + private boolean shouldWriteSettings() { + return getPackageName().equals("android"); + } + private void launchNextStage(boolean locked) { + mClock.animate() + .alpha(0f).scaleX(0.5f).scaleY(0.5f) + .withEndAction(() -> mClock.setVisibility(View.GONE)) + .start(); + + mLogo.setAlpha(0f); + mLogo.setScaleX(0.5f); + mLogo.setScaleY(0.5f); + mLogo.setVisibility(View.VISIBLE); + mLogo.animate() + .alpha(1f) + .scaleX(1f) + .scaleY(1f) + .setInterpolator(new OvershootInterpolator()) + .start(); + + mLogo.postDelayed(() -> { + final ObjectAnimator anim = ObjectAnimator.ofInt(mBg, "level", 0, 10000); + anim.setInterpolator(new DecelerateInterpolator(1f)); + anim.start(); + }, + 500 + ); + final ContentResolver cr = getContentResolver(); try { - if (WRITE_SETTINGS) { + if (shouldWriteSettings()) { + Log.v(TAG, "Saving egg unlock=" + locked); + syncTouchPressure(); Settings.System.putLong(cr, - R_EGG_UNLOCK_SETTING, + S_EGG_UNLOCK_SETTING, locked ? 0 : System.currentTimeMillis()); } } catch (RuntimeException e) { - Log.e("com.android.internal.app.PlatLogoActivity", "Can't write settings", e); + Log.e(TAG, "Can't write settings", e); } try { @@ -151,7 +194,7 @@ public class PlatLogoActivity extends Activity { if (mPressureMax >= 0) { touchData.put("min", mPressureMin); touchData.put("max", mPressureMax); - if (WRITE_SETTINGS) { + if (shouldWriteSettings()) { Settings.System.putString(getContentResolver(), TOUCH_STATS, touchData.toString()); } @@ -173,44 +216,35 @@ public class PlatLogoActivity extends Activity { super.onStop(); } - class BigDialView extends ImageView { - private static final int COLOR_GREEN = 0xff3ddc84; - private static final int COLOR_BLUE = 0xff4285f4; - private static final int COLOR_NAVY = 0xff073042; - private static final int COLOR_ORANGE = 0xfff86734; - private static final int COLOR_CHARTREUSE = 0xffeff7cf; - private static final int COLOR_LIGHTBLUE = 0xffd7effe; - - private static final int STEPS = 11; - private static final float VALUE_CHANGE_MAX = 1f / STEPS; - - private BigDialDrawable mDialDrawable; - private boolean mWasLocked; - - BigDialView(Context context, @Nullable AttributeSet attrs) { - super(context, attrs); - init(); - } - - BigDialView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - init(); - } - - BigDialView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, - int defStyleRes) { - super(context, attrs, defStyleAttr, defStyleRes); - init(); - } + /** + * Subclass of AnalogClock that allows the user to flip up the glass and adjust the hands. + */ + public class SettableAnalogClock extends AnalogClock { + private int mOverrideHour = -1; + private int mOverrideMinute = -1; + private boolean mOverride = false; - private void init() { - mDialDrawable = new BigDialDrawable(); - setImageDrawable(mDialDrawable); + public SettableAnalogClock(Context context) { + super(context); } @Override - public void onDraw(Canvas c) { - super.onDraw(c); + protected Instant now() { + final Instant realNow = super.now(); + final ZoneId tz = Clock.systemDefaultZone().getZone(); + final ZonedDateTime zdTime = realNow.atZone(tz); + if (mOverride) { + if (mOverrideHour < 0) { + mOverrideHour = zdTime.getHour(); + } + return Clock.fixed(zdTime + .withHour(mOverrideHour) + .withMinute(mOverrideMinute) + .withSecond(0) + .toInstant(), tz).instant(); + } else { + return realNow; + } } double toPositiveDegrees(double rad) { @@ -221,226 +255,174 @@ public class PlatLogoActivity extends Activity { public boolean onTouchEvent(MotionEvent ev) { switch (ev.getActionMasked()) { case MotionEvent.ACTION_DOWN: - mWasLocked = mDialDrawable.isLocked(); + mOverride = true; // pass through case MotionEvent.ACTION_MOVE: + measureTouchPressure(ev); + float x = ev.getX(); float y = ev.getY(); - float cx = (getLeft() + getRight()) / 2f; - float cy = (getTop() + getBottom()) / 2f; + float cx = getWidth() / 2f; + float cy = getHeight() / 2f; float angle = (float) toPositiveDegrees(Math.atan2(x - cx, y - cy)); - final int oldLevel = mDialDrawable.getUserLevel(); - mDialDrawable.touchAngle(angle); - final int newLevel = mDialDrawable.getUserLevel(); - if (oldLevel != newLevel) { - performHapticFeedback(newLevel == STEPS - ? HapticFeedbackConstants.CONFIRM - : HapticFeedbackConstants.CLOCK_TICK); + + int minutes = (75 - (int) (angle / 6)) % 60; + int minuteDelta = minutes - mOverrideMinute; + if (minuteDelta != 0) { + if (Math.abs(minuteDelta) > 45 && mOverrideHour >= 0) { + int hourDelta = (minuteDelta < 0) ? 1 : -1; + mOverrideHour = (mOverrideHour + 24 + hourDelta) % 24; + } + mOverrideMinute = minutes; + if (mOverrideMinute == 0) { + performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); + if (getScaleX() == 1f) { + setScaleX(1.05f); + setScaleY(1.05f); + animate().scaleX(1f).scaleY(1f).setDuration(150).start(); + } + } else { + performHapticFeedback(HapticFeedbackConstants.CLOCK_TICK); + } + + onTimeChanged(); + postInvalidate(); } + return true; case MotionEvent.ACTION_UP: - if (mWasLocked != mDialDrawable.isLocked()) { - launchNextStage(mDialDrawable.isLocked()); + if (mOverrideMinute == 0 && (mOverrideHour % 12) == 0) { + Log.v(TAG, "12:00 let's gooooo"); + performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); + launchNextStage(false); } return true; } return false; } + } - @Override - public boolean performClick() { - if (mDialDrawable.getUserLevel() < STEPS - 1) { - mDialDrawable.setUserLevel(mDialDrawable.getUserLevel() + 1); - performHapticFeedback(HapticFeedbackConstants.CLOCK_TICK); - } - return true; - } - - void setUnlockTries(int tries) { - mDialDrawable.setUnlockTries(tries); - } + static class Bubble { + public float x, y, r; + public int color; + } - private class BigDialDrawable extends Drawable { - public final int STEPS = 10; - private int mUnlockTries = 0; - final Paint mPaint = new Paint(); - final Drawable mEleven; - private boolean mNightMode; - private float mValue = 0f; - float mElevenAnim = 0f; - ObjectAnimator mElevenShowAnimator = ObjectAnimator.ofFloat(this, "elevenAnim", 0f, - 1f).setDuration(300); - ObjectAnimator mElevenHideAnimator = ObjectAnimator.ofFloat(this, "elevenAnim", 1f, - 0f).setDuration(500); - - BigDialDrawable() { - mNightMode = getContext().getResources().getConfiguration().isNightModeActive(); - mEleven = getContext().getDrawable(R.drawable.ic_number11); - mElevenShowAnimator.setInterpolator(new PathInterpolator(0.4f, 0f, 0.2f, 1f)); - mElevenHideAnimator.setInterpolator(new PathInterpolator(0.8f, 0.2f, 0.6f, 1f)); - } + class BubblesDrawable extends Drawable { + private static final int MAX_BUBBS = 2000; - public void setUnlockTries(int count) { - if (mUnlockTries != count) { - mUnlockTries = count; - setValue(getValue()); - invalidateSelf(); - } - } + private final int[] mColorIds = { + android.R.color.system_accent1_400, + android.R.color.system_accent1_500, + android.R.color.system_accent1_600, - boolean isLocked() { - return mUnlockTries > 0; - } + android.R.color.system_accent2_400, + android.R.color.system_accent2_500, + android.R.color.system_accent2_600, + }; - public void setValue(float v) { - // until the dial is "unlocked", you can't turn it all the way to 11 - final float max = isLocked() ? 1f - 1f / STEPS : 1f; - mValue = v < 0f ? 0f : v > max ? max : v; - invalidateSelf(); - } + private int[] mColors = new int[mColorIds.length]; - public float getValue() { - return mValue; - } + private final Bubble[] mBubbs = new Bubble[MAX_BUBBS]; + private int mNumBubbs; - public int getUserLevel() { - return Math.round(getValue() * STEPS - 0.25f); - } + private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - public void setUserLevel(int i) { - setValue(getValue() + ((float) i) / STEPS); - } + public float avoid = 0f; + public float padding = 0f; + public float minR = 0f; - public float getElevenAnim() { - return mElevenAnim; + BubblesDrawable() { + for (int i = 0; i < mColorIds.length; i++) { + mColors[i] = getColor(mColorIds[i]); } - - public void setElevenAnim(float f) { - if (mElevenAnim != f) { - mElevenAnim = f; - invalidateSelf(); - } + for (int j = 0; j < mBubbs.length; j++) { + mBubbs[j] = new Bubble(); } + } - @Override - public void draw(@NonNull Canvas canvas) { - final Rect bounds = getBounds(); - final int w = bounds.width(); - final int h = bounds.height(); - final float w2 = w / 2f; - final float h2 = h / 2f; - final float radius = w / 4f; - - canvas.drawColor(mNightMode ? COLOR_NAVY : COLOR_LIGHTBLUE); - - canvas.save(); - canvas.rotate(45, w2, h2); - canvas.clipRect(w2, h2 - radius, Math.min(w, h), h2 + radius); - final int gradientColor = mNightMode ? 0x60000020 : (0x10FFFFFF & COLOR_NAVY); - mPaint.setShader( - new LinearGradient(w2, h2, Math.min(w, h), h2, gradientColor, - 0x00FFFFFF & gradientColor, Shader.TileMode.CLAMP)); - mPaint.setColor(Color.BLACK); - canvas.drawPaint(mPaint); - mPaint.setShader(null); - canvas.restore(); - - mPaint.setStyle(Paint.Style.FILL); - mPaint.setColor(COLOR_GREEN); - - canvas.drawCircle(w2, h2, radius, mPaint); - - mPaint.setColor(mNightMode ? COLOR_LIGHTBLUE : COLOR_NAVY); - final float cx = w * 0.85f; - for (int i = 0; i < STEPS; i++) { - final float f = (float) i / STEPS; - canvas.save(); - final float angle = valueToAngle(f); - canvas.rotate(-angle, w2, h2); - canvas.drawCircle(cx, h2, (i <= getUserLevel()) ? 20 : 5, mPaint); - canvas.restore(); - } - - if (mElevenAnim > 0f) { - final int color = COLOR_ORANGE; - final int size2 = (int) ((0.5 + 0.5f * mElevenAnim) * w / 14); - final float cx11 = cx + size2 / 4f; - mEleven.setBounds((int) cx11 - size2, (int) h2 - size2, - (int) cx11 + size2, (int) h2 + size2); - final int alpha = 0xFFFFFF | ((int) clamp(0xFF * 2 * mElevenAnim, 0, 0xFF) - << 24); - mEleven.setTint(alpha & color); - mEleven.draw(canvas); - } - - // don't want to use the rounded value here since the quantization will be visible - final float angle = valueToAngle(mValue); - - // it's easier to draw at far-right and rotate backwards - canvas.rotate(-angle, w2, h2); - mPaint.setColor(Color.WHITE); - final float dimple = w2 / 12f; - canvas.drawCircle(w - radius - dimple * 2, h2, dimple, mPaint); + @Override + public void draw(Canvas canvas) { + final float f = getLevel() / 10000f; + mPaint.setStyle(Paint.Style.FILL); + int drawn = 0; + for (int j = 0; j < mNumBubbs; j++) { + if (mBubbs[j].color == 0 || mBubbs[j].r == 0) continue; + mPaint.setColor(mBubbs[j].color); + canvas.drawCircle(mBubbs[j].x, mBubbs[j].y, mBubbs[j].r * f, mPaint); + drawn++; } + } - float clamp(float x, float a, float b) { - return x < a ? a : x > b ? b : x; - } + @Override + protected boolean onLevelChange(int level) { + invalidateSelf(); + return true; + } - float angleToValue(float a) { - return 1f - clamp(a / (360 - 45), 0f, 1f); - } + @Override + protected void onBoundsChange(Rect bounds) { + super.onBoundsChange(bounds); + randomize(); + } - // rotation: min is at 4:30, max is at 3:00 - float valueToAngle(float v) { - return (1f - v) * (360 - 45); + private void randomize() { + final float w = getBounds().width(); + final float h = getBounds().height(); + final float maxR = Math.min(w, h) / 3f; + mNumBubbs = 0; + if (avoid > 0f) { + mBubbs[mNumBubbs].x = w / 2f; + mBubbs[mNumBubbs].y = h / 2f; + mBubbs[mNumBubbs].r = avoid; + mBubbs[mNumBubbs].color = 0; + mNumBubbs++; } - - public void touchAngle(float a) { - final int oldUserLevel = getUserLevel(); - final float newValue = angleToValue(a); - // this is how we prevent the knob from snapping from max back to min, or from - // jumping around wherever the user presses. The new value must be pretty close - // to the - // previous one. - if (Math.abs(newValue - getValue()) < VALUE_CHANGE_MAX) { - setValue(newValue); - - if (isLocked() && oldUserLevel != STEPS - 1 && getUserLevel() == STEPS - 1) { - mUnlockTries--; - } else if (!isLocked() && getUserLevel() == 0) { - mUnlockTries = UNLOCK_TRIES; + for (int j = 0; j < MAX_BUBBS; j++) { + // a simple but time-tested bubble-packing algorithm: + // 1. pick a spot + // 2. shrink the bubble until it is no longer overlapping any other bubble + // 3. if the bubble hasn't popped, keep it + int tries = 5; + while (tries-- > 0) { + float x = (float) Math.random() * w; + float y = (float) Math.random() * h; + float r = Math.min(Math.min(x, w - x), Math.min(y, h - y)); + + // shrink radius to fit other bubbs + for (int i = 0; i < mNumBubbs; i++) { + r = (float) Math.min(r, + Math.hypot(x - mBubbs[i].x, y - mBubbs[i].y) - mBubbs[i].r + - padding); + if (r < minR) break; } - if (!isLocked()) { - if (getUserLevel() == STEPS && mElevenAnim != 1f - && !mElevenShowAnimator.isRunning()) { - mElevenHideAnimator.cancel(); - mElevenShowAnimator.start(); - } else if (getUserLevel() != STEPS && mElevenAnim == 1f - && !mElevenHideAnimator.isRunning()) { - mElevenShowAnimator.cancel(); - mElevenHideAnimator.start(); - } + if (r >= minR) { + // we have found a spot for this bubble to live, let's save it and move on + r = Math.min(maxR, r); + + mBubbs[mNumBubbs].x = x; + mBubbs[mNumBubbs].y = y; + mBubbs[mNumBubbs].r = r; + mBubbs[mNumBubbs].color = mColors[(int) (Math.random() * mColors.length)]; + mNumBubbs++; + break; } } } + Log.v(TAG, String.format("successfully placed %d bubbles (%d%%)", + mNumBubbs, (int) (100f * mNumBubbs / MAX_BUBBS))); + } - @Override - public void setAlpha(int i) { - } + @Override + public void setAlpha(int alpha) { } - @Override - public void setColorFilter(@Nullable ColorFilter colorFilter) { - } + @Override + public void setColorFilter(ColorFilter colorFilter) { } - @Override - public int getOpacity() { - return PixelFormat.TRANSLUCENT; - } + @Override + public int getOpacity() { + return TRANSLUCENT; } } -} - - +} diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl index 10f14b42ae42..4f940dbb1d7a 100644 --- a/core/java/com/android/internal/statusbar/IStatusBar.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl @@ -25,6 +25,7 @@ import android.hardware.fingerprint.IUdfpsHbmListener; import android.os.Bundle; import android.os.ParcelFileDescriptor; import android.service.notification.StatusBarNotification; +import android.view.InsetsState; import com.android.internal.statusbar.StatusBarIcon; import com.android.internal.view.AppearanceRegion; @@ -182,7 +183,7 @@ oneway interface IStatusBar /** * Notifies System UI side of system bar attribute change on the specified display. * - * @param displayId the ID of the display to notify + * @param displayId the ID of the display to notify. * @param appearance the appearance of the focused window. The light top bar appearance is not * controlled here, but primaryAppearance and secondaryAppearance. * @param appearanceRegions a set of appearances which will be only applied in their own bounds. @@ -191,11 +192,12 @@ oneway interface IStatusBar * stacks. * @param navbarColorManagedByIme {@code true} if navigation bar color is managed by IME. * @param behavior the behavior of the focused window. - * @param isFullscreen whether any of status or navigation bar is requested invisible. + * @param requestedState the collection of the requested visibilities of system insets. + * @param packageName the package name of the focused app. */ void onSystemBarAttributesChanged(int displayId, int appearance, in AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme, - int behavior, boolean isFullscreen); + int behavior, in InsetsState requestedVisibilities, String packageName); /** * Notifies System UI to show transient bars. The transient bars are system bars, e.g., status diff --git a/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java b/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java index 8fb2f9cd8bf9..2fd1691e5e02 100644 --- a/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java +++ b/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java @@ -21,6 +21,7 @@ import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; import android.util.ArrayMap; +import android.view.InsetsState; import com.android.internal.view.AppearanceRegion; @@ -39,14 +40,15 @@ public final class RegisterStatusBarResult implements Parcelable { public final IBinder mImeToken; public final boolean mNavbarColorManagedByIme; public final int mBehavior; - public final boolean mAppFullscreen; + public final InsetsState mRequestedState; + public final String mPackageName; public final int[] mTransientBarTypes; public RegisterStatusBarResult(ArrayMap<String, StatusBarIcon> icons, int disabledFlags1, int appearance, AppearanceRegion[] appearanceRegions, int imeWindowVis, int imeBackDisposition, boolean showImeSwitcher, int disabledFlags2, IBinder imeToken, - boolean navbarColorManagedByIme, int behavior, boolean appFullscreen, - @NonNull int[] transientBarTypes) { + boolean navbarColorManagedByIme, int behavior, InsetsState requestedState, + String packageName, @NonNull int[] transientBarTypes) { mIcons = new ArrayMap<>(icons); mDisabledFlags1 = disabledFlags1; mAppearance = appearance; @@ -58,7 +60,8 @@ public final class RegisterStatusBarResult implements Parcelable { mImeToken = imeToken; mNavbarColorManagedByIme = navbarColorManagedByIme; mBehavior = behavior; - mAppFullscreen = appFullscreen; + mRequestedState = requestedState; + mPackageName = packageName; mTransientBarTypes = transientBarTypes; } @@ -80,7 +83,8 @@ public final class RegisterStatusBarResult implements Parcelable { dest.writeStrongBinder(mImeToken); dest.writeBoolean(mNavbarColorManagedByIme); dest.writeInt(mBehavior); - dest.writeBoolean(mAppFullscreen); + dest.writeTypedObject(mRequestedState, 0); + dest.writeString(mPackageName); dest.writeIntArray(mTransientBarTypes); } @@ -104,12 +108,13 @@ public final class RegisterStatusBarResult implements Parcelable { final IBinder imeToken = source.readStrongBinder(); final boolean navbarColorManagedByIme = source.readBoolean(); final int behavior = source.readInt(); - final boolean appFullscreen = source.readBoolean(); + final InsetsState requestedState = source.readTypedObject(InsetsState.CREATOR); + final String packageName = source.readString(); final int[] transientBarTypes = source.createIntArray(); return new RegisterStatusBarResult(icons, disabledFlags1, appearance, appearanceRegions, imeWindowVis, imeBackDisposition, showImeSwitcher, disabledFlags2, imeToken, navbarColorManagedByIme, behavior, - appFullscreen, transientBarTypes); + requestedState, packageName, transientBarTypes); } @Override diff --git a/core/java/com/android/internal/view/RecyclerViewCaptureHelper.java b/core/java/com/android/internal/view/RecyclerViewCaptureHelper.java index b29cf1c2cb1a..d14adf6f3c20 100644 --- a/core/java/com/android/internal/view/RecyclerViewCaptureHelper.java +++ b/core/java/com/android/internal/view/RecyclerViewCaptureHelper.java @@ -16,11 +16,6 @@ package com.android.internal.view; -import static com.android.internal.view.ScrollCaptureViewSupport.computeScrollAmount; -import static com.android.internal.view.ScrollCaptureViewSupport.findScrollingReferenceView; -import static com.android.internal.view.ScrollCaptureViewSupport.transformFromContainerToRequest; -import static com.android.internal.view.ScrollCaptureViewSupport.transformFromRequestToContainer; - import android.annotation.NonNull; import android.graphics.Rect; import android.util.Log; @@ -43,6 +38,7 @@ import android.view.ViewParent; */ public class RecyclerViewCaptureHelper implements ScrollCaptureViewHelper<ViewGroup> { private static final String TAG = "RVCaptureHelper"; + private int mScrollDelta; private boolean mScrollBarWasEnabled; private int mOverScrollMode; @@ -61,10 +57,6 @@ public class RecyclerViewCaptureHelper implements ScrollCaptureViewHelper<ViewGr @Override public ScrollResult onScrollRequested(@NonNull ViewGroup recyclerView, Rect scrollBounds, Rect requestRect) { - Log.d(TAG, "-----------------------------------------------------------"); - Log.d(TAG, "onScrollRequested(scrollBounds=" + scrollBounds + ", " - + "requestRect=" + requestRect + ")"); - ScrollResult result = new ScrollResult(); result.requestedArea = new Rect(requestRect); result.scrollDelta = mScrollDelta; @@ -75,61 +67,99 @@ public class RecyclerViewCaptureHelper implements ScrollCaptureViewHelper<ViewGr return result; // result.availableArea == empty Rect } - // Make requestRect relative to RecyclerView (from scrollBounds) - Rect requestedContainerBounds = - transformFromRequestToContainer(mScrollDelta, scrollBounds, requestRect); + // move from scrollBounds-relative to parent-local coordinates + Rect requestedContainerBounds = new Rect(requestRect); + requestedContainerBounds.offset(0, -mScrollDelta); + requestedContainerBounds.offset(scrollBounds.left, scrollBounds.top); + // requestedContainerBounds is now in recyclerview-local coordinates + + // Save a copy for later + View anchor = findChildNearestTarget(recyclerView, requestedContainerBounds); + if (anchor == null) { + Log.w(TAG, "Failed to locate anchor view"); + return result; // result.availableArea == empty rect + } - Rect recyclerLocalVisible = new Rect(); - recyclerView.getLocalVisibleRect(recyclerLocalVisible); + Rect requestedContentBounds = new Rect(requestedContainerBounds); + recyclerView.offsetRectIntoDescendantCoords(anchor, requestedContentBounds); - // Expand request rect match visible bounds to center the requested rect vertically - Rect adjustedContainerBounds = new Rect(requestedContainerBounds); - int remainingHeight = recyclerLocalVisible.height() - requestedContainerBounds.height(); + int prevAnchorTop = anchor.getTop(); + // Note: requestChildRectangleOnScreen may modify rectangle, must pass pass in a copy here + Rect input = new Rect(requestedContentBounds); + // Expand input rect to get the requested rect to be in the center + int remainingHeight = recyclerView.getHeight() - recyclerView.getPaddingTop() + - recyclerView.getPaddingBottom() - input.height(); if (remainingHeight > 0) { - adjustedContainerBounds.inset(0, -remainingHeight / 2); + input.inset(0, -remainingHeight / 2); } - int scrollAmount = computeScrollAmount(recyclerLocalVisible, adjustedContainerBounds); - if (scrollAmount < 0) { - Log.d(TAG, "About to scroll UP (content moves down within parent)"); - } else if (scrollAmount > 0) { - Log.d(TAG, "About to scroll DOWN (content moves up within parent)"); + if (recyclerView.requestChildRectangleOnScreen(anchor, input, true)) { + int scrolled = prevAnchorTop - anchor.getTop(); // inverse of movement + mScrollDelta += scrolled; // view.top-- is equivalent to parent.scrollY++ + result.scrollDelta = mScrollDelta; } - Log.d(TAG, "scrollAmount: " + scrollAmount); - - View refView = findScrollingReferenceView(recyclerView, scrollAmount); - int refTop = refView.getTop(); - - // Map the request into the child view coords - Rect requestedContentBounds = new Rect(adjustedContainerBounds); - recyclerView.offsetRectIntoDescendantCoords(refView, requestedContentBounds); - Log.d(TAG, "request rect, in child view space = " + requestedContentBounds); - // Note: requestChildRectangleOnScreen may modify rectangle, must pass pass in a copy here - Rect request = new Rect(requestedContentBounds); - recyclerView.requestChildRectangleOnScreen(refView, request, true); + requestedContainerBounds.set(requestedContentBounds); + recyclerView.offsetDescendantRectToMyCoords(anchor, requestedContainerBounds); - int scrollDistance = refTop - refView.getTop(); - Log.d(TAG, "Parent view scrolled vertically by " + scrollDistance + " px"); + Rect recyclerLocalVisible = new Rect(scrollBounds); + recyclerView.getLocalVisibleRect(recyclerLocalVisible); - mScrollDelta += scrollDistance; - result.scrollDelta = mScrollDelta; - if (scrollDistance != 0) { - Log.d(TAG, "Scroll delta is now " + mScrollDelta + " px"); + if (!requestedContainerBounds.intersect(recyclerLocalVisible)) { + // Requested area is still not visible + return result; } + Rect available = new Rect(requestedContainerBounds); + available.offset(-scrollBounds.left, -scrollBounds.top); + available.offset(0, mScrollDelta); + result.availableArea = available; + return result; + } - // Update, post-scroll - requestedContainerBounds = new Rect( - transformFromRequestToContainer(mScrollDelta, scrollBounds, requestRect)); - - // in case it might have changed (nested scrolling) - recyclerView.getLocalVisibleRect(recyclerLocalVisible); - if (requestedContainerBounds.intersect(recyclerLocalVisible)) { - result.availableArea = transformFromContainerToRequest( - mScrollDelta, scrollBounds, requestedContainerBounds); + /** + * Find a view that is located "closest" to targetRect. Returns the first view to fully + * vertically overlap the target targetRect. If none found, returns the view with an edge + * nearest the target targetRect. + * + * @param parent the parent vertical layout + * @param targetRect a rectangle in local coordinates of <code>parent</code> + * @return a child view within parent matching the criteria or null + */ + static View findChildNearestTarget(ViewGroup parent, Rect targetRect) { + View selected = null; + int minCenterDistance = Integer.MAX_VALUE; + int maxOverlap = 0; + + // allowable center-center distance, relative to targetRect. + // if within this range, taller views are preferred + final float preferredRangeFromCenterPercent = 0.25f; + final int preferredDistance = + (int) (preferredRangeFromCenterPercent * targetRect.height()); + + Rect parentLocalVis = new Rect(); + parent.getLocalVisibleRect(parentLocalVis); + + Rect frame = new Rect(); + for (int i = 0; i < parent.getChildCount(); i++) { + final View child = parent.getChildAt(i); + child.getHitRect(frame); + + if (child.getVisibility() != View.VISIBLE) { + continue; + } + + int centerDistance = Math.abs(targetRect.centerY() - frame.centerY()); + + if (centerDistance < minCenterDistance) { + // closer to center + minCenterDistance = centerDistance; + selected = child; + } else if (frame.intersect(targetRect) && (frame.height() > preferredDistance)) { + // within X% pixels of center, but taller + selected = child; + } } - Log.d(TAG, "-----------------------------------------------------------"); - return result; + return selected; } @Override diff --git a/core/java/com/android/internal/view/ScrollCaptureInternal.java b/core/java/com/android/internal/view/ScrollCaptureInternal.java index ffee16a151df..e3a9fda7b000 100644 --- a/core/java/com/android/internal/view/ScrollCaptureInternal.java +++ b/core/java/com/android/internal/view/ScrollCaptureInternal.java @@ -34,7 +34,7 @@ public class ScrollCaptureInternal { private static final String TAG = "ScrollCaptureInternal"; // Log found scrolling views - private static final boolean DEBUG = true; + private static final boolean DEBUG = false; // Log all investigated views, as well as heuristic checks private static final boolean DEBUG_VERBOSE = false; diff --git a/core/java/com/android/internal/widget/ConversationHeaderLinearLayout.java b/core/java/com/android/internal/widget/ConversationHeaderLinearLayout.java new file mode 100644 index 000000000000..481183e700a2 --- /dev/null +++ b/core/java/com/android/internal/widget/ConversationHeaderLinearLayout.java @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.widget; + +import android.annotation.Nullable; +import android.content.Context; +import android.util.AttributeSet; +import android.view.View; +import android.widget.LinearLayout; +import android.widget.RemoteViews; + +import java.util.LinkedList; +import java.util.List; + +/** + * This is a subclass of LinearLayout meant to be used in the Conversation header, to fix a bug + * when multiple user-provided strings are shown in the same conversation header. b/189723284 + * + * This works around a deficiency in LinearLayout when shrinking views that it can't fully reduce + * all contents if any of the oversized views reaches zero. + */ +@RemoteViews.RemoteView +public class ConversationHeaderLinearLayout extends LinearLayout { + + public ConversationHeaderLinearLayout(Context context) { + super(context); + } + + public ConversationHeaderLinearLayout(Context context, + @Nullable AttributeSet attrs) { + super(context, attrs); + } + + public ConversationHeaderLinearLayout(Context context, @Nullable AttributeSet attrs, + int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + private int calculateTotalChildLength() { + final int count = getChildCount(); + int totalLength = 0; + + for (int i = 0; i < count; ++i) { + final View child = getChildAt(i); + if (child == null || child.getVisibility() == GONE) { + continue; + } + final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) + child.getLayoutParams(); + totalLength += child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin; + } + return totalLength + getPaddingLeft() + getPaddingRight(); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + + final int containerWidth = getMeasuredWidth(); + final int contentsWidth = calculateTotalChildLength(); + + int excessContents = contentsWidth - containerWidth; + if (excessContents <= 0) { + return; + } + final int count = getChildCount(); + + float remainingWeight = 0; + List<ViewInfo> visibleChildrenToShorten = null; + + // Find children which need to be shortened in order to ensure the contents fit. + for (int i = 0; i < count; ++i) { + final View child = getChildAt(i); + if (child == null || child.getVisibility() == View.GONE) { + continue; + } + final float weight = ((LayoutParams) child.getLayoutParams()).weight; + if (weight == 0) { + continue; + } + if (child.getMeasuredWidth() == 0) { + continue; + } + if (visibleChildrenToShorten == null) { + visibleChildrenToShorten = new LinkedList<>(); + } + visibleChildrenToShorten.add(new ViewInfo(child)); + remainingWeight += Math.max(0, weight); + } + if (visibleChildrenToShorten == null || visibleChildrenToShorten.isEmpty()) { + return; + } + balanceViewWidths(visibleChildrenToShorten, remainingWeight, excessContents); + remeasureChangedChildren(visibleChildrenToShorten); + } + + /** + * Measure any child with a width that has changed. + */ + private void remeasureChangedChildren(List<ViewInfo> childrenInfo) { + for (ViewInfo info : childrenInfo) { + if (info.mWidth != info.mStartWidth) { + final int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec( + Math.max(0, info.mWidth), MeasureSpec.EXACTLY); + final int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec( + info.mView.getMeasuredHeight(), MeasureSpec.EXACTLY); + info.mView.measure(childWidthMeasureSpec, childHeightMeasureSpec); + } + } + } + + /** + * Given a list of view, use the weights to remove width from each view proportionally to the + * weight (and ignoring the view's actual width), but do this iteratively whenever a view is + * reduced to zero width, because in that case other views need reduction. + */ + void balanceViewWidths(List<ViewInfo> viewInfos, float weightSum, int excessContents) { + boolean performAnotherPass = true; + // Loops only when all of the following are true: + // * `performAnotherPass` -- a view clamped to 0 width (or the first iteration) + // * `excessContents > 0` -- there is still horizontal space to allocate + // * `weightSum > 0` -- at least 1 view with nonzero width AND nonzero weight left + while (performAnotherPass && excessContents > 0 && weightSum > 0) { + int excessRemovedDuringThisPass = 0; + float weightSumForNextPass = 0; + performAnotherPass = false; + for (ViewInfo info : viewInfos) { + if (info.mWeight <= 0) { + continue; + } + if (info.mWidth <= 0) { + continue; + } + int newWidth = (int) (info.mWidth - (excessContents * (info.mWeight / weightSum))); + if (newWidth < 0) { + newWidth = 0; + performAnotherPass = true; + } + excessRemovedDuringThisPass += info.mWidth - newWidth; + info.mWidth = newWidth; + if (info.mWidth > 0) { + weightSumForNextPass += info.mWeight; + } + } + excessContents -= excessRemovedDuringThisPass; + weightSum = weightSumForNextPass; + } + } + + /** + * A helper class for measuring children. + */ + static class ViewInfo { + final View mView; + final float mWeight; + final int mStartWidth; + int mWidth; + + ViewInfo(View view) { + this.mView = view; + this.mWeight = ((LayoutParams) view.getLayoutParams()).weight; + this.mStartWidth = this.mWidth = view.getMeasuredWidth(); + } + } +} diff --git a/core/java/com/android/internal/widget/NotificationExpandButton.java b/core/java/com/android/internal/widget/NotificationExpandButton.java index 1974b0c2e5fc..07ee9b5d2ff1 100644 --- a/core/java/com/android/internal/widget/NotificationExpandButton.java +++ b/core/java/com/android/internal/widget/NotificationExpandButton.java @@ -20,7 +20,6 @@ import android.annotation.ColorInt; import android.annotation.Nullable; import android.content.Context; import android.content.res.ColorStateList; -import android.graphics.PorterDuff; import android.graphics.Rect; import android.util.AttributeSet; import android.view.RemotableViewMethod; @@ -159,8 +158,7 @@ public class NotificationExpandButton extends FrameLayout { if (mHighlightPillColor != 0) { mPillView.setBackgroundTintList(ColorStateList.valueOf(mHighlightPillColor)); } - mPillView.setBackgroundTintMode(PorterDuff.Mode.SRC_IN); - mIconView.setColorFilter(mHighlightTextColor, PorterDuff.Mode.SRC_IN); + mIconView.setColorFilter(mHighlightTextColor); if (mHighlightTextColor != 0) { mNumberView.setTextColor(mHighlightTextColor); } @@ -168,8 +166,7 @@ public class NotificationExpandButton extends FrameLayout { if (mDefaultPillColor != 0) { mPillView.setBackgroundTintList(ColorStateList.valueOf(mDefaultPillColor)); } - mPillView.setBackgroundTintMode(PorterDuff.Mode.SRC_IN); - mIconView.setColorFilter(mDefaultTextColor, PorterDuff.Mode.SRC_IN); + mIconView.setColorFilter(mDefaultTextColor); if (mDefaultTextColor != 0) { mNumberView.setTextColor(mDefaultTextColor); } diff --git a/core/jni/android_hardware_camera2_CameraMetadata.cpp b/core/jni/android_hardware_camera2_CameraMetadata.cpp index 5c9999dc0c85..5293c583cfd0 100644 --- a/core/jni/android_hardware_camera2_CameraMetadata.cpp +++ b/core/jni/android_hardware_camera2_CameraMetadata.cpp @@ -16,6 +16,7 @@ */ // #define LOG_NDEBUG 0 +#include <memory> #define LOG_TAG "CameraMetadata-JNI" #include <utils/Errors.h> #include <utils/Log.h> @@ -162,6 +163,8 @@ struct Helpers { extern "C" { +static void CameraMetadata_setVendorId(JNIEnv* env, jclass thiz, jlong ptr, + jlong vendorId); static jobject CameraMetadata_getAllVendorKeys(JNIEnv* env, jclass thiz, jlong ptr, jclass keyType); static jint CameraMetadata_getTagFromKey(JNIEnv *env, jclass thiz, jstring keyName, @@ -596,6 +599,9 @@ static void CameraMetadata_writeToParcel(JNIEnv *env, jclass thiz, jobject parce static const JNINativeMethod gCameraMetadataMethods[] = { // static methods + { "nativeSetVendorId", + "(JJ)V", + (void *)CameraMetadata_setVendorId }, { "nativeGetTagFromKey", "(Ljava/lang/String;J)I", (void *)CameraMetadata_getTagFromKey }, @@ -870,6 +876,27 @@ static jobject CameraMetadata_getAllVendorKeys(JNIEnv* env, jclass thiz, jlong p return arrayList; } +static void CameraMetadata_setVendorId(JNIEnv *env, jclass thiz, jlong ptr, + jlong vendorId) { + ALOGV("%s", __FUNCTION__); + + CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, ptr); + + if (metadata == NULL) { + ALOGW("%s: Returning early due to exception being thrown", + __FUNCTION__); + return; + } + if (metadata->isEmpty()) { + std::unique_ptr<CameraMetadata> emptyBuffer = std::make_unique<CameraMetadata>(10); + metadata->swap(*emptyBuffer); + } + + camera_metadata_t *meta = const_cast<camera_metadata_t *>(metadata->getAndLock()); + set_camera_metadata_vendor_id(meta, vendorId); + metadata->unlock(meta); +} + static jint CameraMetadata_getTagFromKey(JNIEnv *env, jclass thiz, jstring keyName, jlong vendorId) { ScopedUtfChars keyScoped(env, keyName); diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp index 6e2b9cf250c6..0ec296b42328 100644 --- a/core/jni/android_media_AudioSystem.cpp +++ b/core/jni/android_media_AudioSystem.cpp @@ -207,6 +207,7 @@ static struct { jmethodID getId; jmethodID getResonantFrequency; jmethodID getQFactor; + jmethodID getMaxAmplitude; } gVibratorMethods; static Mutex gLock; @@ -2677,6 +2678,8 @@ static jint android_media_AudioSystem_setVibratorInfos(JNIEnv *env, jobject thiz vibratorInfo.resonantFrequency = env->CallFloatMethod(jVibrator.get(), gVibratorMethods.getResonantFrequency); vibratorInfo.qFactor = env->CallFloatMethod(jVibrator.get(), gVibratorMethods.getQFactor); + vibratorInfo.maxAmplitude = + env->CallFloatMethod(jVibrator.get(), gVibratorMethods.getMaxAmplitude); vibratorInfos.push_back(vibratorInfo); } return (jint)check_AudioSystem_Command(AudioSystem::setVibratorInfos(vibratorInfos)); @@ -3041,6 +3044,8 @@ int register_android_media_AudioSystem(JNIEnv *env) gVibratorMethods.getResonantFrequency = GetMethodIDOrDie(env, vibratorClass, "getResonantFrequency", "()F"); gVibratorMethods.getQFactor = GetMethodIDOrDie(env, vibratorClass, "getQFactor", "()F"); + gVibratorMethods.getMaxAmplitude = + GetMethodIDOrDie(env, vibratorClass, "getHapticChannelMaximumAmplitude", "()F"); AudioSystem::addErrorCallback(android_media_AudioSystem_error_callback); diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp index de65b894e677..41804480122c 100644 --- a/core/jni/android_os_Debug.cpp +++ b/core/jni/android_os_Debug.cpp @@ -880,7 +880,7 @@ static jlong android_os_Debug_getGpuDmaBufUsageKb(JNIEnv* env, jobject clazz) { continue; } - sizeKb += importer_info->second.size; + sizeKb += importer_info->second.size / 1024; } return sizeKb; diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index c0de5d96719a..dd80c731fbce 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -1798,6 +1798,14 @@ static void nativeSetTransformHint(JNIEnv* env, jclass clazz, jlong nativeSurfac ui::Transform::toRotationFlags(static_cast<ui::Rotation>(transformHint))); } +static jint nativeGetTransformHint(JNIEnv* env, jclass clazz, jlong nativeSurfaceControl) { + sp<SurfaceControl> surface(reinterpret_cast<SurfaceControl*>(nativeSurfaceControl)); + ui::Transform::RotationFlags transformHintRotationFlags = + static_cast<ui::Transform::RotationFlags>(surface->getTransformHint()); + + return toRotationInt(ui::Transform::toRotation((transformHintRotationFlags))); +} + // ---------------------------------------------------------------------------- static const JNINativeMethod sSurfaceControlMethods[] = { @@ -1989,6 +1997,8 @@ static const JNINativeMethod sSurfaceControlMethods[] = { (void*)nativeGetGPUContextPriority }, {"nativeSetTransformHint", "(JI)V", (void*)nativeSetTransformHint }, + {"nativeGetTransformHint", "(J)I", + (void*)nativeGetTransformHint }, // clang-format on }; diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index 64bf47cee6ec..d49d21565757 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -2602,6 +2602,7 @@ static jint com_android_internal_os_Zygote_nativeCurrentTaggingLevel(JNIEnv* env case PR_MTE_TCF_SYNC: return MEMORY_TAG_LEVEL_SYNC; case PR_MTE_TCF_ASYNC: + case PR_MTE_TCF_ASYNC | PR_MTE_TCF_SYNC: return MEMORY_TAG_LEVEL_ASYNC; default: ALOGE("Unknown memory tagging level: %i", level); diff --git a/core/proto/android/hardware/sensorprivacy.proto b/core/proto/android/hardware/sensorprivacy.proto index 401e0038cada..d52af5c6fe67 100644 --- a/core/proto/android/hardware/sensorprivacy.proto +++ b/core/proto/android/hardware/sensorprivacy.proto @@ -65,4 +65,22 @@ message SensorPrivacyIndividualEnabledSensorProto { // If sensor privacy is enabled for this sensor optional bool is_enabled = 2; +} + +message SensorPrivacyToggleSourceProto { + option (android.msg_privacy).dest = DEST_AUTOMATIC; + + enum Source { + UNKNOWN = 0; + + QS_TILE = 1; + SETTINGS = 2; + DIALOG = 3; + SHELL = 4; + OTHER = 5; + } + + // Source for which sensor privacy was toggled. + optional Source source = 1; + }
\ No newline at end of file diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 14d200d00d56..4dec0ffccb5e 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -4053,6 +4053,9 @@ For more details, see <a href="{@docRoot}about/versions/12/behavior-changes-12#exact-alarm-permission"> Exact alarm permission</a>. + <p>Apps who hold this permission and target API level 31 or above, always stay in the + {@link android.app.usage.UsageStatsManager#STANDBY_BUCKET_WORKING_SET WORKING_SET} or + lower standby bucket. Applications targeting API level 30 or below do not need this permission to use exact alarm APIs. --> @@ -5899,8 +5902,8 @@ android:process=":ui"> </activity> <activity android:name="com.android.internal.app.PlatLogoActivity" - android:theme="@style/Theme.DeviceDefault.DayNight" - android:configChanges="orientation|keyboardHidden" + android:theme="@style/Theme.DeviceDefault.Wallpaper.NoTitleBar" + android:configChanges="orientation|screenSize|screenLayout|keyboardHidden" android:icon="@drawable/platlogo" android:process=":ui"> </activity> diff --git a/core/res/res/drawable-hdpi/clock_dial.png b/core/res/res/drawable-hdpi/clock_dial.png Binary files differdeleted file mode 100644 index 9de29bc0e53e..000000000000 --- a/core/res/res/drawable-hdpi/clock_dial.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/clock_hand_hour.png b/core/res/res/drawable-hdpi/clock_hand_hour.png Binary files differdeleted file mode 100644 index 9f7e5c02d49c..000000000000 --- a/core/res/res/drawable-hdpi/clock_hand_hour.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/clock_hand_minute.png b/core/res/res/drawable-hdpi/clock_hand_minute.png Binary files differdeleted file mode 100644 index 2eec38060c45..000000000000 --- a/core/res/res/drawable-hdpi/clock_hand_minute.png +++ /dev/null diff --git a/core/res/res/drawable-ldpi/clock_dial.png b/core/res/res/drawable-ldpi/clock_dial.png Binary files differdeleted file mode 100644 index cbc996185cc7..000000000000 --- a/core/res/res/drawable-ldpi/clock_dial.png +++ /dev/null diff --git a/core/res/res/drawable-ldpi/clock_hand_hour.png b/core/res/res/drawable-ldpi/clock_hand_hour.png Binary files differdeleted file mode 100644 index 3362fd0775d5..000000000000 --- a/core/res/res/drawable-ldpi/clock_hand_hour.png +++ /dev/null diff --git a/core/res/res/drawable-ldpi/clock_hand_minute.png b/core/res/res/drawable-ldpi/clock_hand_minute.png Binary files differdeleted file mode 100644 index 5c73d45ada5c..000000000000 --- a/core/res/res/drawable-ldpi/clock_hand_minute.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/clock_dial.png b/core/res/res/drawable-mdpi/clock_dial.png Binary files differdeleted file mode 100644 index 82f73fec0423..000000000000 --- a/core/res/res/drawable-mdpi/clock_dial.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/clock_hand_hour.png b/core/res/res/drawable-mdpi/clock_hand_hour.png Binary files differdeleted file mode 100644 index 1f0aec80ba14..000000000000 --- a/core/res/res/drawable-mdpi/clock_hand_hour.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/clock_hand_minute.png b/core/res/res/drawable-mdpi/clock_hand_minute.png Binary files differdeleted file mode 100644 index 6cd8a4bfa48d..000000000000 --- a/core/res/res/drawable-mdpi/clock_hand_minute.png +++ /dev/null diff --git a/core/res/res/drawable-nodpi/clock_dial.xml b/core/res/res/drawable-nodpi/clock_dial.xml new file mode 100644 index 000000000000..5263218ef880 --- /dev/null +++ b/core/res/res/drawable-nodpi/clock_dial.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="utf-8"?> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="380dp" + android:height="380dp" + android:viewportWidth="380" + android:viewportHeight="380"> + <path + android:pathData="M177.389,2.803C185.381,-0.934 194.619,-0.934 202.611,2.803L231.193,16.169C234.358,17.649 237.76,18.56 241.242,18.861L272.677,21.577C281.467,22.336 289.468,26.956 294.52,34.188L312.59,60.054C314.591,62.919 317.081,65.409 319.946,67.41L345.812,85.48C353.044,90.533 357.664,98.533 358.423,107.323L361.139,138.758C361.44,142.24 362.351,145.642 363.832,148.807L377.197,177.389C380.934,185.381 380.934,194.619 377.197,202.611L363.832,231.193C362.351,234.359 361.44,237.76 361.139,241.242L358.423,272.677C357.664,281.467 353.044,289.468 345.812,294.52L319.946,312.59C317.081,314.591 314.591,317.081 312.59,319.946L294.52,345.812C289.468,353.044 281.467,357.664 272.677,358.423L241.242,361.139C237.76,361.44 234.359,362.351 231.193,363.832L202.611,377.197C194.619,380.934 185.381,380.934 177.389,377.197L148.807,363.832C145.642,362.351 142.24,361.44 138.758,361.139L107.323,358.423C98.533,357.664 90.533,353.044 85.48,345.812L67.41,319.946C65.409,317.081 62.919,314.591 60.054,312.59L34.188,294.52C26.956,289.468 22.336,281.467 21.577,272.677L18.861,241.242C18.56,237.76 17.649,234.359 16.169,231.193L2.803,202.611C-0.934,194.619 -0.934,185.381 2.803,177.389L16.169,148.807C17.649,145.642 18.56,142.24 18.861,138.758L21.577,107.323C22.336,98.533 26.956,90.533 34.188,85.48L60.054,67.41C62.919,65.409 65.409,62.919 67.41,60.054L85.48,34.188C90.533,26.956 98.533,22.336 107.323,21.577L138.758,18.861C142.24,18.56 145.642,17.649 148.807,16.169L177.389,2.803Z" + android:fillColor="@color/system_neutral1_200"/> +</vector> diff --git a/core/res/res/drawable-nodpi/clock_hand_hour.xml b/core/res/res/drawable-nodpi/clock_hand_hour.xml new file mode 100644 index 000000000000..de165a429a57 --- /dev/null +++ b/core/res/res/drawable-nodpi/clock_hand_hour.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="utf-8"?> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="380dp" + android:height="380dp" + android:viewportWidth="380" + android:viewportHeight="380"> + <path + android:pathData="M190,96L190,96A16,16 0,0 1,206 112L206,190A16,16 0,0 1,190 206L190,206A16,16 0,0 1,174 190L174,112A16,16 0,0 1,190 96z" + android:fillColor="@color/system_accent1_700"/> +</vector> diff --git a/core/res/res/drawable-nodpi/clock_hand_minute.xml b/core/res/res/drawable-nodpi/clock_hand_minute.xml new file mode 100644 index 000000000000..72cac6e88597 --- /dev/null +++ b/core/res/res/drawable-nodpi/clock_hand_minute.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="utf-8"?> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="380dp" + android:height="380dp" + android:viewportWidth="380" + android:viewportHeight="380"> + <path + android:pathData="M190,60L190,60A16,16 0,0 1,206 76L206,190A16,16 0,0 1,190 206L190,206A16,16 0,0 1,174 190L174,76A16,16 0,0 1,190 60z" + android:fillColor="@color/system_accent2_500"/> +</vector> diff --git a/core/res/res/drawable-nodpi/platlogo.xml b/core/res/res/drawable-nodpi/platlogo.xml index b01eb3944b50..1d67570cf485 100644 --- a/core/res/res/drawable-nodpi/platlogo.xml +++ b/core/res/res/drawable-nodpi/platlogo.xml @@ -1,50 +1,36 @@ +<!-- +Copyright (C) 2021 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="512dp" - android:height="512dp" - android:viewportWidth="512" - android:viewportHeight="512"> - <path - android:fillColor="#F86734" - android:pathData="M416.23 236.62h-10.67c-1.46 0-2.65-1.19-2.65-2.65v-9.85c0-1.47 1.19-2.65 2.65-2.65h23.37c1.47 0 2.66 1.19 2.66 2.65v66.9c0 1.46-1.2 2.65-2.66 2.65H418.9c-1.47 0-2.66-1.19-2.66-2.65v-54.4z"/> - <path - android:fillColor="#F86734" - android:pathData="M455.51 236.62h-10.67c-1.47 0-2.65-1.19-2.65-2.65v-9.85c0-1.47 1.18-2.65 2.65-2.65h23.37c1.47 0 2.66 1.19 2.66 2.65v66.9c0 1.46-1.2 2.65-2.66 2.65h-10.05c-1.46 0-2.65-1.19-2.65-2.65v-54.4z"/> - <path - android:fillColor="#D6F0FF" - android:pathData="M364.12 400.25a4.34 4.34 0 1 0 0 8.68a4.34 4.34 0 1 0 0-8.68z"/> - <path - android:fillColor="#D6F0FF" - android:pathData="M275.46 433.53a4.84 4.84 0 1 0 0 9.68a4.84 4.84 0 1 0 0-9.68z"/> - <path - android:fillColor="#D6F0FF" - android:pathData="M184.52 418.83a5.36 5.36 0 1 0 0 10.72a5.36 5.36 0 1 0 0-10.72z"/> - <path - android:fillColor="#D6F0FF" - android:pathData="M110.42 359.19a5.89 5.89 0 1 0 0 11.78a5.89 5.89 0 1 0 0-11.78z"/> - <path - android:fillColor="#D6F0FF" - android:pathData="M75.94 270.17a6.43 6.43 0 1 0 0 12.86a6.43 6.43 0 1 0 0-12.86z"/> - <path - android:fillColor="#D6F0FF" - android:pathData="M89.48 178.57a6.98 6.98 0 1 0 0 13.96a6.98 6.98 0 1 0 0-13.96z"/> - <path - android:fillColor="#D6F0FF" - android:pathData="M147.97 103.54a7.54 7.54 0 1 0 0 15.08a7.54 7.54 0 1 0 0-15.08z"/> - <path - android:fillColor="#D6F0FF" - android:pathData="M236.63 66.7a8.1 8.1 0 1 0 0 16.2a8.1 8.1 0 1 0 0-16.2z"/> - <path - android:fillColor="#D6F0FF" - android:pathData="M327.09 78.3a8.66 8.66 0 1 0 0 17.32a8.66 8.66 0 1 0 0-17.32z"/> - <path - android:fillColor="#D6F0FF" - android:pathData="M401.05 136.97a9.22 9.22 0 1 0 0 18.44a9.22 9.22 0 1 0 0-18.44z"/> - <group> - <path - android:fillColor="#3DDB85" - android:pathData="M255.45 129.46a128.11 128.11 0 1 0 0 256.22a128.11 128.11 0 1 0 0-256.22z"/> - <path - android:fillColor="#FFF" - android:pathData="M339.23 236.09a21.48 21.48 0 1 0 0 42.96a21.48 21.48 0 1 0 0-42.96z"/> - </group> + android:width="128dp" + android:height="128dp" + android:viewportWidth="128" + android:viewportHeight="128"> + <path + android:pathData="M64,64m-64,0a64,64 0,1 1,128 0a64,64 0,1 1,-128 0" + android:fillColor="@android:color/system_accent3_500"/> + <path + android:pathData="M32.5,34.15a10,10 0,0 1,9.94 10V93.85" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#fff" + android:strokeLineCap="round"/> + <path + android:pathData="M95.5,93.85H55.71V83.9A19.9,19.9 0,0 1,75.61 64h10a9.94,9.94 0,0 0,9.94 -10,19.9 19.9,0 0,0 -38.69,-6.56A20.77,20.77 0,0 0,56 50.73" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#fff" + android:strokeLineCap="round"/> </vector> diff --git a/core/res/res/drawable-xhdpi/clock_dial.png b/core/res/res/drawable-xhdpi/clock_dial.png Binary files differdeleted file mode 100644 index 6cb60a296ed8..000000000000 --- a/core/res/res/drawable-xhdpi/clock_dial.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/clock_hand_hour.png b/core/res/res/drawable-xhdpi/clock_hand_hour.png Binary files differdeleted file mode 100644 index bc0c5bd4d59f..000000000000 --- a/core/res/res/drawable-xhdpi/clock_hand_hour.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/clock_hand_minute.png b/core/res/res/drawable-xhdpi/clock_hand_minute.png Binary files differdeleted file mode 100644 index 01d611fbbdcd..000000000000 --- a/core/res/res/drawable-xhdpi/clock_hand_minute.png +++ /dev/null diff --git a/core/res/res/drawable/ic_lock.xml b/core/res/res/drawable/ic_lock.xml index 7582d5f82c1d..c30f96330378 100644 --- a/core/res/res/drawable/ic_lock.xml +++ b/core/res/res/drawable/ic_lock.xml @@ -14,14 +14,23 @@ Copyright (C) 2019 The Android Open Source Project limitations under the License. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="32dp" - android:height="32dp" - android:viewportWidth="32.0" - android:viewportHeight="32.0"> + android:width="26dp" + android:height="36dp" + android:viewportWidth="26" + android:viewportHeight="36"> <path android:fillColor="#FF000000" - android:pathData="M16,20m-2.5,0a2.5,2.5 0,1 1,5 0a2.5,2.5 0,1 1,-5 0"/> + android:pathData="M13.75 27.5 C15.13,27.5 16.25,26.38 16.25,25 C16.25,23.62 15.13,22.5 13.75,22.5 C12.37,22.5 11.25,23.62 11.25,25 C11.25,26.38 12.37,27.5 13.75,27.5c " /> <path - android:fillColor="#FF000000" - android:pathData="M24,11h-2.3V7.3c0,-3.1 -2.5,-5.7 -5.7,-5.7c-3.1,0 -5.7,2.5 -5.7,5.7V11H8c-1.3,0 -2.3,1 -2.3,2.3v13.3c0,1.3 1,2.3 2.3,2.3h16c1.3,0 2.3,-1 2.3,-2.3V13.3C26.3,12 25.3,11 24,11zM12.3,7.3c0,-2 1.6,-3.7 3.7,-3.7c2,0 3.7,1.6 3.7,3.7V11h-7.3V7.3zM24.3,26.7c0,0.2 -0.1,0.3 -0.3,0.3H8c-0.2,0 -0.3,-0.1 -0.3,-0.3V13.3C7.7,13.1 7.8,13 8,13h16c0.2,0 0.3,0.1 0.3,0.3V26.7z"/> + android:strokeColor="#FF000000" + android:strokeLineCap="round" + android:strokeLineJoin="round" + android:strokeWidth="2.5" + android:pathData="M4.5 15 C4.5,15 23,15 23,15 C24.1,15 25,15.9 25,17 C25,17 25,33 25,33 C25,34.1 24.1,35 23,35 C23,35 4.5,35 4.5,35 C3.4,35 2.5,34.1 2.5,33 C2.5,33 2.5,17 2.5,17 C2.5,15.9 3.4,15 4.5,15c " /> + <path + android:strokeColor="#FF000000" + android:strokeLineCap="round" + android:strokeLineJoin="round" + android:strokeWidth="2.5" + android:pathData="M7.5 15 C7.5,15 7.5,8.61 7.5,8.61 C7.5,5.24 10.3,2.5 13.75,2.5 C17.2,2.5 20,5.24 20,8.61 C20,8.61 20,15 20,15 " /> </vector>
\ No newline at end of file diff --git a/core/res/res/drawable/ic_lock_open.xml b/core/res/res/drawable/ic_lock_open.xml index e0deb598b1b1..abe6ddebb845 100644 --- a/core/res/res/drawable/ic_lock_open.xml +++ b/core/res/res/drawable/ic_lock_open.xml @@ -14,14 +14,23 @@ Copyright (C) 2019 The Android Open Source Project limitations under the License. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="32dp" - android:height="32dp" - android:viewportWidth="32.0" - android:viewportHeight="32.0"> + android:height="36dp" + android:width="34dp" + android:viewportHeight="36" + android:viewportWidth="34"> <path android:fillColor="#FF000000" - android:pathData="M16,20m-2.5,0a2.5,2.5 0,1 1,5 0a2.5,2.5 0,1 1,-5 0"/> + android:pathData="M13.75 27.5 C15.13,27.5 16.25,26.38 16.25,25 C16.25,23.62 15.13,22.5 13.75,22.5 C12.37,22.5 11.25,23.62 11.25,25 C11.25,26.38 12.37,27.5 13.75,27.5c " /> <path - android:fillColor="#FF000000" - android:pathData="M25.3,1.7c-3.1,0 -5.7,2.5 -5.7,5.7V11H8c-1.3,0 -2.3,1 -2.3,2.3v13.3c0,1.3 1,2.3 2.3,2.3h16c1.3,0 2.3,-1 2.3,-2.3V13.3c0,-1.3 -1,-2.3 -2.3,-2.3h-2.3V7.3c0,-2 1.6,-3.7 3.7,-3.7c2,0 3.7,1.6 3.7,3.7V8h2V7.3C31,4.2 28.5,1.7 25.3,1.7zM24.3,13.3v13.3c0,0.2 -0.1,0.3 -0.3,0.3H8c-0.2,0 -0.3,-0.1 -0.3,-0.3V13.3C7.7,13.1 7.8,13 8,13h16C24.2,13 24.3,13.1 24.3,13.3z"/> + android:strokeColor="#FF000000" + android:strokeLineCap="round" + android:strokeLineJoin="round" + android:strokeWidth="2.5" + android:pathData=" M4.5 15 C4.5,15 23,15 23,15 C24.1,15 25,15.9 25,17 C25,17 25,33 25,33 C25,34.1 24.1,35 23,35 C23,35 4.5,35 4.5,35 C3.4,35 2.5,34.1 2.5,33 C2.5,33 2.5,17 2.5,17 C2.5,15.9 3.4,15 4.5,15c " /> + <path + android:strokeColor="#FF000000" + android:strokeLineCap="round" + android:strokeLineJoin="round" + android:strokeWidth="2.5" + android:pathData="M20 15 C20,15 20,8.61 20,8.61 C20,5.24 22.8,2.5 26.25,2.5 C29.7,2.5 32.5,5.24 32.5,8.61 C32.5,8.61 32.5,15 32.5,15 " /> </vector>
\ No newline at end of file diff --git a/core/res/res/layout/notification_template_conversation_header.xml b/core/res/res/layout/notification_template_conversation_header.xml index 389637eb2517..2faff412565e 100644 --- a/core/res/res/layout/notification_template_conversation_header.xml +++ b/core/res/res/layout/notification_template_conversation_header.xml @@ -14,7 +14,7 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License --> -<LinearLayout +<com.android.internal.widget.ConversationHeaderLinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/conversation_header" android:layout_width="wrap_content" @@ -119,6 +119,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="@dimen/notification_conversation_header_separating_margin" + android:layout_weight="100" android:showRelative="true" android:singleLine="true" android:visibility="gone" @@ -171,4 +172,4 @@ android:src="@drawable/ic_notifications_alerted" android:visibility="gone" /> -</LinearLayout> +</com.android.internal.widget.ConversationHeaderLinearLayout> diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml index 6fcef4f5ed0e..f05e18fa2ce3 100644 --- a/core/res/res/values-as/strings.xml +++ b/core/res/res/values-as/strings.xml @@ -610,14 +610,14 @@ <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"ফিংগাৰপ্ৰিণ্ট আইকন"</string> - <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"মুখাৱয়বৰ দ্বাৰা আনলক কৰাৰ সুবিধা"</string> - <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"মুখাৱয়বৰ দ্বাৰা আনলক কৰাৰ সুবিধাটোৰ ব্যৱহাৰ কৰোঁতে সমস্যা হৈছে"</string> + <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"ফেচ আনলক"</string> + <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"ফেচ আনলক ব্যৱহাৰ কৰোঁতে সমস্যা হৈছে"</string> <string name="face_recalibrate_notification_content" msgid="3064513770251355594">"আপোনাৰ মুখাৱয়বৰ মডেলটো মচিবলৈ টিপক, তাৰ পাছত পুনৰ আপোনাৰ মুখাৱয়ব যোগ দিয়ক"</string> - <string name="face_setup_notification_title" msgid="8843461561970741790">"মুখাৱয়বৰে আনলক কৰাৰ সুবিধাটো ছেট আপ কৰক"</string> + <string name="face_setup_notification_title" msgid="8843461561970741790">"ফেচ আনলক সুবিধাটো ছেট আপ কৰক"</string> <string name="face_setup_notification_content" msgid="5463999831057751676">"আপোনাৰ ফ’নটোলৈ চাই সেইটো আনলক কৰক"</string> <string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"আনলক কৰাৰ অধিক উপায় ছেট আপ কৰক"</string> <string name="fingerprint_setup_notification_content" msgid="205578121848324852">"এটা ফিংগাৰপ্ৰিণ্ট যোগ দিবলৈ টিপক"</string> - <string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"ফিংগাৰপ্ৰিণ্টৰ দ্বাৰা আনলক কৰা সুবিধা"</string> + <string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"ফিংগাৰপ্ৰিন্ট আনলক"</string> <string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"ফিংগাৰপ্ৰিণ্ট ছেন্সৰ ব্যৱহাৰ কৰিব নোৱাৰি"</string> <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"মেৰামতি সেৱা প্ৰদানকাৰী কোনো প্ৰতিষ্ঠানলৈ যাওক।"</string> <string name="face_acquired_insufficient" msgid="2150805835949162453">"সঠিক মুখমণ্ডলৰ ডেটা কেপচাৰ নহ’ল। আকৌ চেষ্টা কৰক।"</string> @@ -643,19 +643,19 @@ <string-array name="face_acquired_vendor"> </string-array> <string name="face_error_hw_not_available" msgid="5085202213036026288">"মুখমণ্ডল সত্যাপন কৰিব পৰা নগ’ল। হাৰ্ডৱেৰ নাই।"</string> - <string name="face_error_timeout" msgid="2598544068593889762">"পুনৰ মুখাৱয়বৰ দ্বাৰা আনলক কৰাটো ব্যৱহাৰ কৰি চাওক"</string> + <string name="face_error_timeout" msgid="2598544068593889762">"ফেচ আনলক পুনৰ ব্যৱহাৰ কৰি চাওক"</string> <string name="face_error_no_space" msgid="5649264057026021723">"নতুন মুখমণ্ডলৰ ডেটা জমা কৰিব পৰা নাই। প্ৰথমে পুৰণি এখন মচক।"</string> <string name="face_error_canceled" msgid="2164434737103802131">"মুখমণ্ডলৰ প্ৰক্ৰিয়া বাতিল কৰা হ’ল।"</string> - <string name="face_error_user_canceled" msgid="5766472033202928373">"ব্যৱহাৰকাৰীয়ে মুখাৱয়বৰ দ্বাৰা আনলক কৰাৰ সুবিধাটো বাতিল কৰিছে"</string> + <string name="face_error_user_canceled" msgid="5766472033202928373">"ব্যৱহাৰকাৰীয়ে ফেচ আনলক বাতিল কৰিছে"</string> <string name="face_error_lockout" msgid="7864408714994529437">"অত্যধিক ভুল প্ৰয়াস। কিছুসময়ৰ পাছত আকৌ চেষ্টা কৰক।"</string> - <string name="face_error_lockout_permanent" msgid="3277134834042995260">"অতি বেছিসংখ্যক প্ৰয়াস। মুখাৱয়বৰ দ্বাৰা আনলক কৰাৰ সুবিধাটো অক্ষম কৰা হৈছে।"</string> + <string name="face_error_lockout_permanent" msgid="3277134834042995260">"অতি বেছিসংখ্যক প্ৰয়াস। ফেচ আনলক সুবিধাটো অক্ষম কৰা হৈছে।"</string> <string name="face_error_lockout_screen_lock" msgid="5062609811636860928">"অতি বেছিসংখ্যক প্ৰয়াস। ইয়াৰ সলনি স্ক্ৰীন লক দিয়ক।"</string> <string name="face_error_unable_to_process" msgid="5723292697366130070">"মুখমণ্ডল সত্যাপন কৰিব পৰা নগ’ল। আকৌ চেষ্টা কৰক।"</string> - <string name="face_error_not_enrolled" msgid="1134739108536328412">"আপুনি মুখাৱয়বৰ দ্বাৰা আনলক কৰাৰ সুবিধাটো ছেট আপ কৰা নাই"</string> - <string name="face_error_hw_not_present" msgid="7940978724978763011">"এই ডিভাইচটোত মুখাৱয়বৰ দ্বাৰা আনলক কৰাৰ সুবিধাটো সমৰ্থিত নহয়"</string> + <string name="face_error_not_enrolled" msgid="1134739108536328412">"ফেচ আনলক সুবিধাটো ছেট আপ কৰা নাই"</string> + <string name="face_error_hw_not_present" msgid="7940978724978763011">"এই ডিভাইচটোত ফেচ আনলক সুবিধাটো সমৰ্থিত নহয়"</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"ছেন্সৰটো সাময়িকভাৱে অক্ষম হৈ আছে।"</string> <string name="face_name_template" msgid="3877037340223318119">"মুখমণ্ডল <xliff:g id="FACEID">%d</xliff:g>"</string> - <string name="face_app_setting_name" msgid="5854024256907828015">"মুখাৱয়বৰে আনলক কৰাটো ব্যৱহাৰ কৰক"</string> + <string name="face_app_setting_name" msgid="5854024256907828015">"ফেচ আনলক ব্যৱহাৰ কৰক"</string> <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"ফেচ আনলক অথবা স্ক্ৰীন লক ব্যৱহাৰ কৰক"</string> <string name="face_dialog_default_subtitle" msgid="6620492813371195429">"অব্যাহত ৰাখিবলৈ নিজৰ মুখাৱয়ব ব্যৱহাৰ কৰক"</string> <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"অব্যাহত ৰাখিবলৈ আপোনাৰ মুখাৱয়ব অথবা স্ক্ৰীন লক ব্যৱহাৰ কৰক"</string> @@ -958,7 +958,7 @@ <string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"আনলক ক্ষেত্ৰ বিস্তাৰ কৰক।"</string> <string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"শ্লাইডৰদ্বাৰা আনলক।"</string> <string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"আৰ্হিৰদ্বাৰা আনলক।"</string> - <string name="keyguard_accessibility_face_unlock" msgid="4533832120787386728">"মুখাৱয়বৰ দ্বাৰা আনলক কৰাৰ সুবিধা।"</string> + <string name="keyguard_accessibility_face_unlock" msgid="4533832120787386728">"ফেচ আনলক।"</string> <string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"পিনৰদ্বাৰা আনলক।"</string> <string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"ছিম পিন আনলক।"</string> <string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"ছিম পিইউকে আনলক।"</string> diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml index f58abbdecd21..47bcbe189570 100644 --- a/core/res/res/values-bn/strings.xml +++ b/core/res/res/values-bn/strings.xml @@ -610,7 +610,7 @@ <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"আঙ্গুলের ছাপ আইকন"</string> - <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"\'ফেস আনলক\'"</string> + <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"ফেস আনলক"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"\'ফেস আনলক\' ফিচার ব্যবহার করার ক্ষেত্রে হওয়া সমস্যা"</string> <string name="face_recalibrate_notification_content" msgid="3064513770251355594">"আপনার ফেস মডেল মুছে দেওয়ার জন্য ট্যাপ করুন এবং তারপরে আবার ফেস যোগ করুন"</string> <string name="face_setup_notification_title" msgid="8843461561970741790">"\'ফেস আনলক\' সেট আপ করুন"</string> @@ -958,7 +958,7 @@ <string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"আনলক এলাকা প্রসারিত করুন৷"</string> <string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"স্লাইড দিয়ে আনলক৷"</string> <string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"প্যাটার্ন দিয়ে আনলক৷"</string> - <string name="keyguard_accessibility_face_unlock" msgid="4533832120787386728">"\'ফেস আনলক\'।"</string> + <string name="keyguard_accessibility_face_unlock" msgid="4533832120787386728">"ফেস আনলক।"</string> <string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"পিন দিয়ে আনলক৷"</string> <string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"সিম পিন আনলক।"</string> <string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"সিম পিইউকে আনলক।"</string> @@ -1482,8 +1482,7 @@ <string name="deny" msgid="6632259981847676572">"অস্বীকার করুন"</string> <string name="permission_request_notification_title" msgid="1810025922441048273">"অনুমতির অনুরোধ করা হয়েছে"</string> <string name="permission_request_notification_with_subtitle" msgid="3743417870360129298">"<xliff:g id="ACCOUNT">%s</xliff:g>অ্যাকাউন্টের জন্য\nঅনুমতির অনুরোধ করা হয়েছে৷"</string> - <!-- no translation found for permission_request_notification_for_app_with_subtitle (1298704005732851350) --> - <skip /> + <string name="permission_request_notification_for_app_with_subtitle" msgid="1298704005732851350">"<xliff:g id="ACCOUNT">%2$s</xliff:g> অ্যাকাউন্টের জন্য <xliff:g id="APP">%1$s</xliff:g>\n থেকে অনুমতি চাওয়া হয়েছে।"</string> <string name="forward_intent_to_owner" msgid="4620359037192871015">"আপনি এই অ্যাপ্লিকেশানটি আপনার কর্মস্থলের প্রোফাইলের বাইরে ব্যবহার করছেন"</string> <string name="forward_intent_to_work" msgid="3620262405636021151">"আপনি এই অ্যাপ্লিকেশানটি আপনার কর্মস্থলের প্রোফাইলে ব্যবহার করছেন"</string> <string name="input_method_binding_label" msgid="1166731601721983656">"ইনপুট পদ্ধতি"</string> diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml index baa8da028fa5..d4705c100a8f 100644 --- a/core/res/res/values-eu/strings.xml +++ b/core/res/res/values-eu/strings.xml @@ -643,7 +643,7 @@ <string-array name="face_acquired_vendor"> </string-array> <string name="face_error_hw_not_available" msgid="5085202213036026288">"Ezin da egiaztatu aurpegia. Hardwarea ez dago erabilgarri."</string> - <string name="face_error_timeout" msgid="2598544068593889762">"Saiatu berriro aurpegiaren bidez desblokeatzen"</string> + <string name="face_error_timeout" msgid="2598544068593889762">"Saiatu berriro aurpegi bidez desblokeatzen"</string> <string name="face_error_no_space" msgid="5649264057026021723">"Ezin dira gorde aurpegiaren datu berriak. Ezabatu zaharrak."</string> <string name="face_error_canceled" msgid="2164434737103802131">"Utzi da aurpegiaren bidezko eragiketa."</string> <string name="face_error_user_canceled" msgid="5766472033202928373">"Erabiltzaileak aurpegi bidez desblokeatzeko aukera utzi du"</string> diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml index ea160bc335c8..860e10bcff4d 100644 --- a/core/res/res/values-fr-rCA/strings.xml +++ b/core/res/res/values-fr-rCA/strings.xml @@ -541,10 +541,10 @@ <string name="permdesc_bluetooth_advertise" product="default" msgid="6085174451034210183">"Permet à l\'application d\'envoyer des annonces aux appareils Bluetooth à proximité"</string> <string name="permlab_uwb_ranging" msgid="8141915781475770665">"déterminer la position relative entre des appareils à bande ultralarge à proximité"</string> <string name="permdesc_uwb_ranging" msgid="2519723069604307055">"Autorisez l\'application à déterminer la position relative entre des appareils à bande ultralarge à proximité"</string> - <string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Information sur le service préféré de paiement NFC"</string> - <string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Permet à l\'application d\'obtenir de l\'information sur le service préféré de paiement NFC comme les aides enregistrées et la route de destination."</string> + <string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Information sur le service préféré de paiement CCP"</string> + <string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Permet à l\'application d\'obtenir de l\'information sur le service préféré de paiement CCP comme les aides enregistrées et la route de destination."</string> <string name="permlab_nfc" msgid="1904455246837674977">"gérer la communication en champ proche"</string> - <string name="permdesc_nfc" msgid="8352737680695296741">"Permet à l\'application de communiquer avec des bornes, des cartes et des lecteurs compatibles avec la technologie NFC (communication en champ proche)."</string> + <string name="permdesc_nfc" msgid="8352737680695296741">"Permet à l\'application de communiquer avec des bornes, des cartes et des lecteurs compatibles avec la technologie CCP (communication en champ proche)."</string> <string name="permlab_disableKeyguard" msgid="3605253559020928505">"désactiver le verrouillage de l\'écran"</string> <string name="permdesc_disableKeyguard" msgid="3223710003098573038">"Permet à l\'application de désactiver le verrouillage des touches et toute mesure de sécurité par mot de passe associée. Par exemple, votre téléphone désactive le verrouillage des touches lorsque vous recevez un appel, puis le réactive lorsque vous raccrochez."</string> <string name="permlab_requestPasswordComplexity" msgid="1808977190557794109">"demander la complexité du verrouillage d\'écran"</string> @@ -1511,7 +1511,7 @@ <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Touchez pour quitter l\'application de conduite."</string> <string name="back_button_label" msgid="4078224038025043387">"Précédent"</string> <string name="next_button_label" msgid="6040209156399907780">"Suivante"</string> - <string name="skip_button_label" msgid="3566599811326688389">"Passer"</string> + <string name="skip_button_label" msgid="3566599811326688389">"Ignorer"</string> <string name="no_matches" msgid="6472699895759164599">"Aucune partie"</string> <string name="find_on_page" msgid="5400537367077438198">"Rechercher sur la page"</string> <plurals name="matches_found" formatted="false" msgid="1101758718194295554"> diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index e71c2498837e..2f8deaf97111 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -613,7 +613,7 @@ <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Déverrouillage par reconnaissance faciale"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problème lié au déverrouillage par reconnaissance faciale"</string> <string name="face_recalibrate_notification_content" msgid="3064513770251355594">"Appuyez pour supprimer votre empreinte faciale, puis ajoutez de nouveau votre visage"</string> - <string name="face_setup_notification_title" msgid="8843461561970741790">"Configurer le déverrouillage facial"</string> + <string name="face_setup_notification_title" msgid="8843461561970741790">"Configurer le déverrouillage par reconnaissance faciale"</string> <string name="face_setup_notification_content" msgid="5463999831057751676">"Déverrouillez votre téléphone en le regardant"</string> <string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Configurer d\'autres méthodes de déverrouillage"</string> <string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Appuyez pour ajouter une empreinte digitale"</string> @@ -1071,7 +1071,7 @@ <string name="weeks" msgid="3516247214269821391">"semaines"</string> <string name="year" msgid="5182610307741238982">"année"</string> <string name="years" msgid="5797714729103773425">"années"</string> - <string name="now_string_shortest" msgid="3684914126941650330">"mainten."</string> + <string name="now_string_shortest" msgid="3684914126941650330">"maintenant"</string> <plurals name="duration_minutes_shortest" formatted="false" msgid="7519574894537185135"> <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> m</item> <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> m</item> diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml index 12b80d4fbeda..f51a9a5c8fe0 100644 --- a/core/res/res/values-gu/strings.xml +++ b/core/res/res/values-gu/strings.xml @@ -1482,8 +1482,7 @@ <string name="deny" msgid="6632259981847676572">"નકારો"</string> <string name="permission_request_notification_title" msgid="1810025922441048273">"પરવાનગીની વિનંતી કરી"</string> <string name="permission_request_notification_with_subtitle" msgid="3743417870360129298">"એકાઉન્ટ <xliff:g id="ACCOUNT">%s</xliff:g> માટે\nપરવાનગીની વિનંતી કરી."</string> - <!-- no translation found for permission_request_notification_for_app_with_subtitle (1298704005732851350) --> - <skip /> + <string name="permission_request_notification_for_app_with_subtitle" msgid="1298704005732851350">"<xliff:g id="ACCOUNT">%2$s</xliff:g> એકાઉન્ટ માટે\n<xliff:g id="APP">%1$s</xliff:g> દ્વારા પરવાનગીની વિનંતી કરવામાં આવી."</string> <string name="forward_intent_to_owner" msgid="4620359037192871015">"તમે તમારી કાર્ય પ્રોફાઇલની બહાર આ એપ્લિકેશનનો ઉપયોગ કરી રહ્યાં છો"</string> <string name="forward_intent_to_work" msgid="3620262405636021151">"તમે તમારી કાર્ય પ્રોફાઇલમાં આ એપ્લિકેશનનો ઉપયોગ કરી રહ્યાં છો"</string> <string name="input_method_binding_label" msgid="1166731601721983656">"ઇનપુટ પદ્ધતિ"</string> diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml index d7730d73e5f5..6919a3dc6c7c 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -2285,7 +2285,7 @@ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string> <string name="window_magnification_prompt_title" msgid="2876703640772778215">"Nuove impostazioni per l\'ingrandimento"</string> <string name="window_magnification_prompt_content" msgid="8159173903032344891">"Ora puoi ingrandire parte dello schermo"</string> - <string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Attiva nelle Impostazioni"</string> + <string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Attiva in Impostazioni"</string> <string name="dismiss_action" msgid="1728820550388704784">"Ignora"</string> <string name="sensor_privacy_start_use_mic_notification_content_title" msgid="2420858361276370367">"Sblocca il microfono del dispositivo"</string> <string name="sensor_privacy_start_use_camera_notification_content_title" msgid="7287720213963466672">"Sblocca la fotocamera del dispositivo"</string> diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml index 3243a8d35359..6e8281326606 100644 --- a/core/res/res/values-kk/strings.xml +++ b/core/res/res/values-kk/strings.xml @@ -611,7 +611,7 @@ </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Саусақ ізі белгішесі"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Бет тану"</string> - <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Face Unlock функциясына қатысты мәселе шықты"</string> + <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Бет тану функциясына қатысты мәселе шықты"</string> <string name="face_recalibrate_notification_content" msgid="3064513770251355594">"Бет үлгісін жою үшін түртіңіз, содан соң жаңа бет үлгісін қосыңыз."</string> <string name="face_setup_notification_title" msgid="8843461561970741790">"Бет тану функциясын реттеу"</string> <string name="face_setup_notification_content" msgid="5463999831057751676">"Телефоныңызға қарап, оның құлпын ашыңыз."</string> diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml index d9fd1037c902..f5d16fcb3f7f 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -579,7 +579,7 @@ <string name="fingerprint_acquired_partial" msgid="694598777291084823">"지문의 일부만 감지됨"</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"지문을 인식할 수 없습니다. 다시 시도해 주세요."</string> <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"센서 닦기"</string> - <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"조금 더 오래 기다려 주세요."</string> + <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"조금 더 길게 터치하세요."</string> <string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"손가락을 너무 느리게 움직였습니다. 다시 시도해 주세요."</string> <string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"다른 지문으로 시도"</string> <string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"너무 밝음"</string> diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml index 8fddef017996..174d7324dda9 100644 --- a/core/res/res/values-ky/strings.xml +++ b/core/res/res/values-ky/strings.xml @@ -648,7 +648,7 @@ <string name="face_error_canceled" msgid="2164434737103802131">"Жүздүн аныктыгын текшерүү жокко чыгарылды."</string> <string name="face_error_user_canceled" msgid="5766472033202928373">"Жүзүнөн таанып ачуу функциясын колдонуучу өчүрүп салды"</string> <string name="face_error_lockout" msgid="7864408714994529437">"Өтө көп жолу аракет жасадыңыз. Бир аздан кийин кайталап көрүңүз."</string> - <string name="face_error_lockout_permanent" msgid="3277134834042995260">"Өтө көп жолу аракет кылдыңыз. Жүзүнөн таануу функциясы өчүрүлдү."</string> + <string name="face_error_lockout_permanent" msgid="3277134834042995260">"Өтө көп жолу аракет кылдыңыз. Жүзүнөн таанып ачуу функциясы өчүрүлдү."</string> <string name="face_error_lockout_screen_lock" msgid="5062609811636860928">"Өтө көп жолу аракет кылдыңыз. Эрканды кулпулоо функциясын колдонуңуз."</string> <string name="face_error_unable_to_process" msgid="5723292697366130070">"Жүз ырасталбай жатат. Кайталап көрүңүз."</string> <string name="face_error_not_enrolled" msgid="1134739108536328412">"Жүзүнөн таанып ачуу функциясын жөндөй элексиз"</string> @@ -1482,7 +1482,7 @@ <string name="deny" msgid="6632259981847676572">"Уруксат берилбейт"</string> <string name="permission_request_notification_title" msgid="1810025922441048273">"Уруксат талап кылуу"</string> <string name="permission_request_notification_with_subtitle" msgid="3743417870360129298">"Кийинки эсепке\nуруксат талап кылынууда: <xliff:g id="ACCOUNT">%s</xliff:g>."</string> - <string name="permission_request_notification_for_app_with_subtitle" msgid="1298704005732851350">"<xliff:g id="APP">%1$s</xliff:g> колдонмосу\n <xliff:g id="ACCOUNT">%2$s</xliff:g> аккаунтуна кирүүгө уруксат сурады."</string> + <string name="permission_request_notification_for_app_with_subtitle" msgid="1298704005732851350">"<xliff:g id="APP">%1$s</xliff:g> колдонмосу\n<xliff:g id="ACCOUNT">%2$s</xliff:g> аккаунтуна кирүүгө уруксат сурады."</string> <string name="forward_intent_to_owner" msgid="4620359037192871015">"Бул колдонмо жумуш профилиңиздин сыртында колдонулуп жатат"</string> <string name="forward_intent_to_work" msgid="3620262405636021151">"Бул колдонмону жумуш профилиңизде пайдаланып жатасыз"</string> <string name="input_method_binding_label" msgid="1166731601721983656">"Киргизүү ыкмасы"</string> diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml index 31d0762ec523..b29d49ef8dbe 100644 --- a/core/res/res/values-mk/strings.xml +++ b/core/res/res/values-mk/strings.xml @@ -617,7 +617,7 @@ <string name="face_setup_notification_content" msgid="5463999831057751676">"Отклучете го телефонот со гледање во него"</string> <string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Поставете уште начини за отклучување"</string> <string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Допрете за да додадете отпечаток"</string> - <string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Отклучување со отпечаток"</string> + <string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Отклучување со отпечаток на прст"</string> <string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Не може да се користи сензорот за отпечатоци"</string> <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Однесете го на поправка."</string> <string name="face_acquired_insufficient" msgid="2150805835949162453">"Не се сними прецизна слика. Обидете се повторно."</string> diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml index 26c5a3b75c16..75857ff45ccb 100644 --- a/core/res/res/values-nl/strings.xml +++ b/core/res/res/values-nl/strings.xml @@ -610,10 +610,10 @@ <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Vingerafdruk-icoon"</string> - <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Ontgrendelen via gezicht"</string> + <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Ontgrendelen via gezichtsherkenning"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Probleem met Ontgrendelen via gezichtsherkenning"</string> <string name="face_recalibrate_notification_content" msgid="3064513770251355594">"Tik om je gezichtsmodel te verwijderen en voeg je gezicht opnieuw toe"</string> - <string name="face_setup_notification_title" msgid="8843461561970741790">"Ontgrendeling via gezichtsherkenning instellen"</string> + <string name="face_setup_notification_title" msgid="8843461561970741790">"Ontgrendelen via gezichtsherkenning instellen"</string> <string name="face_setup_notification_content" msgid="5463999831057751676">"Ontgrendel je telefoon door ernaar te kijken"</string> <string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Stel meer manieren in om te ontgrendelen"</string> <string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Tik om een vingerafdruk toe te voegen"</string> diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml index a94236190cdb..c45ac41462ae 100644 --- a/core/res/res/values-pl/strings.xml +++ b/core/res/res/values-pl/strings.xml @@ -250,7 +250,7 @@ <string name="global_action_power_off" msgid="4404936470711393203">"Wyłącz"</string> <string name="global_action_power_options" msgid="1185286119330160073">"Przycisk zasilania"</string> <string name="global_action_restart" msgid="4678451019561687074">"Uruchom ponownie"</string> - <string name="global_action_emergency" msgid="1387617624177105088">"Nagły przypadek"</string> + <string name="global_action_emergency" msgid="1387617624177105088">"Połączenie alarmowe"</string> <string name="global_action_bug_report" msgid="5127867163044170003">"Zgłoś błąd"</string> <string name="global_action_logout" msgid="6093581310002476511">"Zakończ sesję"</string> <string name="global_action_screenshot" msgid="2610053466156478564">"Zrzut ekranu"</string> diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml index 05787342c253..8198ae939e3b 100644 --- a/core/res/res/values-pt-rBR/strings.xml +++ b/core/res/res/values-pt-rBR/strings.xml @@ -611,9 +611,9 @@ </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ícone de impressão digital"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Desbloqueio facial"</string> - <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problema com o desbloqueio facial"</string> + <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problema com o Desbloqueio facial"</string> <string name="face_recalibrate_notification_content" msgid="3064513770251355594">"Toque para excluir seu modelo de rosto e crie um novo"</string> - <string name="face_setup_notification_title" msgid="8843461561970741790">"Configurar o desbloqueio facial"</string> + <string name="face_setup_notification_title" msgid="8843461561970741790">"Configurar o Desbloqueio facial"</string> <string name="face_setup_notification_content" msgid="5463999831057751676">"Desbloqueie o smartphone olhando para ele"</string> <string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Configure mais formas de desbloquear a tela"</string> <string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Toque para adicionar uma impressão digital"</string> @@ -643,7 +643,7 @@ <string-array name="face_acquired_vendor"> </string-array> <string name="face_error_hw_not_available" msgid="5085202213036026288">"Impossível verificar rosto. Hardware indisponível."</string> - <string name="face_error_timeout" msgid="2598544068593889762">"Tente usar o desbloqueio facial novamente"</string> + <string name="face_error_timeout" msgid="2598544068593889762">"Tente usar o Desbloqueio facial novamente"</string> <string name="face_error_no_space" msgid="5649264057026021723">"Não é possível salvar dados faciais. Exclua dados antigos."</string> <string name="face_error_canceled" msgid="2164434737103802131">"Operação facial cancelada."</string> <string name="face_error_user_canceled" msgid="5766472033202928373">"Desbloqueio facial cancelado pelo usuário"</string> @@ -651,11 +651,11 @@ <string name="face_error_lockout_permanent" msgid="3277134834042995260">"Muitas tentativas. Desbloqueio facial desativado."</string> <string name="face_error_lockout_screen_lock" msgid="5062609811636860928">"Muitas tentativas. Como alternativa, use o bloqueio de tela."</string> <string name="face_error_unable_to_process" msgid="5723292697366130070">"Não é possível verificar o rosto. Tente novamente."</string> - <string name="face_error_not_enrolled" msgid="1134739108536328412">"O desbloqueio facial não foi configurado"</string> - <string name="face_error_hw_not_present" msgid="7940978724978763011">"O dispositivo não é compatível com o desbloqueio facial"</string> + <string name="face_error_not_enrolled" msgid="1134739108536328412">"O Desbloqueio facial não foi configurado"</string> + <string name="face_error_hw_not_present" msgid="7940978724978763011">"O dispositivo não é compatível com o Desbloqueio facial"</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"Sensor desativado temporariamente."</string> <string name="face_name_template" msgid="3877037340223318119">"Rosto <xliff:g id="FACEID">%d</xliff:g>"</string> - <string name="face_app_setting_name" msgid="5854024256907828015">"Usar o desbloqueio facial"</string> + <string name="face_app_setting_name" msgid="5854024256907828015">"Usar o Desbloqueio facial"</string> <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Usar reconhecimento facial ou bloqueio de tela"</string> <string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Use seu rosto para continuar"</string> <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Use seu rosto ou o bloqueio de tela para continuar"</string> diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml index 05787342c253..8198ae939e3b 100644 --- a/core/res/res/values-pt/strings.xml +++ b/core/res/res/values-pt/strings.xml @@ -611,9 +611,9 @@ </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ícone de impressão digital"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Desbloqueio facial"</string> - <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problema com o desbloqueio facial"</string> + <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problema com o Desbloqueio facial"</string> <string name="face_recalibrate_notification_content" msgid="3064513770251355594">"Toque para excluir seu modelo de rosto e crie um novo"</string> - <string name="face_setup_notification_title" msgid="8843461561970741790">"Configurar o desbloqueio facial"</string> + <string name="face_setup_notification_title" msgid="8843461561970741790">"Configurar o Desbloqueio facial"</string> <string name="face_setup_notification_content" msgid="5463999831057751676">"Desbloqueie o smartphone olhando para ele"</string> <string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Configure mais formas de desbloquear a tela"</string> <string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Toque para adicionar uma impressão digital"</string> @@ -643,7 +643,7 @@ <string-array name="face_acquired_vendor"> </string-array> <string name="face_error_hw_not_available" msgid="5085202213036026288">"Impossível verificar rosto. Hardware indisponível."</string> - <string name="face_error_timeout" msgid="2598544068593889762">"Tente usar o desbloqueio facial novamente"</string> + <string name="face_error_timeout" msgid="2598544068593889762">"Tente usar o Desbloqueio facial novamente"</string> <string name="face_error_no_space" msgid="5649264057026021723">"Não é possível salvar dados faciais. Exclua dados antigos."</string> <string name="face_error_canceled" msgid="2164434737103802131">"Operação facial cancelada."</string> <string name="face_error_user_canceled" msgid="5766472033202928373">"Desbloqueio facial cancelado pelo usuário"</string> @@ -651,11 +651,11 @@ <string name="face_error_lockout_permanent" msgid="3277134834042995260">"Muitas tentativas. Desbloqueio facial desativado."</string> <string name="face_error_lockout_screen_lock" msgid="5062609811636860928">"Muitas tentativas. Como alternativa, use o bloqueio de tela."</string> <string name="face_error_unable_to_process" msgid="5723292697366130070">"Não é possível verificar o rosto. Tente novamente."</string> - <string name="face_error_not_enrolled" msgid="1134739108536328412">"O desbloqueio facial não foi configurado"</string> - <string name="face_error_hw_not_present" msgid="7940978724978763011">"O dispositivo não é compatível com o desbloqueio facial"</string> + <string name="face_error_not_enrolled" msgid="1134739108536328412">"O Desbloqueio facial não foi configurado"</string> + <string name="face_error_hw_not_present" msgid="7940978724978763011">"O dispositivo não é compatível com o Desbloqueio facial"</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"Sensor desativado temporariamente."</string> <string name="face_name_template" msgid="3877037340223318119">"Rosto <xliff:g id="FACEID">%d</xliff:g>"</string> - <string name="face_app_setting_name" msgid="5854024256907828015">"Usar o desbloqueio facial"</string> + <string name="face_app_setting_name" msgid="5854024256907828015">"Usar o Desbloqueio facial"</string> <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Usar reconhecimento facial ou bloqueio de tela"</string> <string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Use seu rosto para continuar"</string> <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Use seu rosto ou o bloqueio de tela para continuar"</string> diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml index 89494f235493..132ee6f261c7 100644 --- a/core/res/res/values-si/strings.xml +++ b/core/res/res/values-si/strings.xml @@ -610,14 +610,14 @@ <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"ඇඟිලි සලකුණු නිරූපකය"</string> - <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"මුහුණෙන් අගුළු ඇරීම"</string> + <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"මුහුණෙන් අගුළු හැරීම"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"මුහුණෙන් අගුලු හැරීම සම්බන්ධව ගැටලුවකි"</string> <string name="face_recalibrate_notification_content" msgid="3064513770251355594">"ඔබගේ මුහුණත ආකෘතිය මැකීමට තට්ටු කරන්න, අනතුරුව ඔබගේ මුහුණ නැවත එක් කරන්න"</string> - <string name="face_setup_notification_title" msgid="8843461561970741790">"මුහුණෙන් අගුළු ඇරීම පිහිටුවන්න"</string> + <string name="face_setup_notification_title" msgid="8843461561970741790">"මුහුණෙන් අගුළු හැරීම පිහිටුවන්න"</string> <string name="face_setup_notification_content" msgid="5463999831057751676">"ඔබගේ දුරකථනය දෙස බැලීමෙන් එහි අගුලු හරින්න"</string> <string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"අගුලු හැරීමට තවත් ක්රම සකසන්න"</string> <string name="fingerprint_setup_notification_content" msgid="205578121848324852">"ඇඟිලි සලකුණක් එක් කිරීමට තට්ටු කරන්න"</string> - <string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"ඇඟිලි සලකුණු අගුළු ඇරීම"</string> + <string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"ඇඟිලි සලකුණු අගුළු හැරීම"</string> <string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"ඇඟිලි සලකුණු සංවේදකය භාවිත කළ නොහැකිය"</string> <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"අළුත්වැඩියා සැපයුම්කරුවෙකු බලන්න."</string> <string name="face_acquired_insufficient" msgid="2150805835949162453">"නිරවද්ය මුහුණු දත්ත ගත නොහැකි විය. නැවත උත්සාහ කරන්න."</string> @@ -643,19 +643,19 @@ <string-array name="face_acquired_vendor"> </string-array> <string name="face_error_hw_not_available" msgid="5085202213036026288">"මුහුණ සත්යාපනය කළ නොහැක. දෘඩාංගය නොමැත."</string> - <string name="face_error_timeout" msgid="2598544068593889762">"මුහුණෙන් අගුළු ඇරීම නැවත උත්සාහ කරන්න."</string> + <string name="face_error_timeout" msgid="2598544068593889762">"මුහුණෙන් අගුළු හැරීම නැවත උත්සාහ කරන්න."</string> <string name="face_error_no_space" msgid="5649264057026021723">"නව මුහුණු දත්ත ගබඩා කළ නොහැක. පළමුව පැරණි එකක් මකන්න."</string> <string name="face_error_canceled" msgid="2164434737103802131">"මුහුණු මෙහෙයුම අවලංගු කරන ලදී."</string> - <string name="face_error_user_canceled" msgid="5766472033202928373">"පරිශීලකයා විසින් මුහුණෙන් අගුළු ඇරීම අවලංගු කරන ලදි"</string> + <string name="face_error_user_canceled" msgid="5766472033202928373">"පරිශීලකයා විසින් මුහුණෙන් අගුළු හැරීම අවලංගු කරන ලදි"</string> <string name="face_error_lockout" msgid="7864408714994529437">"උත්සාහයන් ඉතා වැඩි ගණනකි. පසුව නැවත උත්සාහ කරන්න."</string> - <string name="face_error_lockout_permanent" msgid="3277134834042995260">"උත්සාහයන් ඉතා වැඩි ගණනකි. මුහුණෙන් අගුළු ඇරීම අබලයි."</string> + <string name="face_error_lockout_permanent" msgid="3277134834042995260">"උත්සාහයන් ඉතා වැඩි ගණනකි. මුහුණෙන් අගුළු හැරීම අබලයි."</string> <string name="face_error_lockout_screen_lock" msgid="5062609811636860928">"උත්සාහයන් ඉතා වැඩි ගණනකි. ඒ වෙනුවට තිර අගුල ඇතුළු කරන්න."</string> <string name="face_error_unable_to_process" msgid="5723292697366130070">"මුහුණ සත්යාපන කළ නොහැක. නැවත උත්සාහ කරන්න."</string> - <string name="face_error_not_enrolled" msgid="1134739108536328412">"ඔබ මුහුණෙන් අගුළු ඇරීම පිහිටුවා නැත"</string> - <string name="face_error_hw_not_present" msgid="7940978724978763011">"මුහුණෙන් අගුළු ඇරීම මෙම උපාංගයේ සහාය නොදක්වයි."</string> + <string name="face_error_not_enrolled" msgid="1134739108536328412">"ඔබ මුහුණෙන් අගුළු හැරීම පිහිටුවා නැත"</string> + <string name="face_error_hw_not_present" msgid="7940978724978763011">"මුහුණෙන් අගුළු හැරීම මෙම උපාංගයේ සහාය නොදක්වයි."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"සංවේදකය තාවකාලිකව අබල කර ඇත."</string> <string name="face_name_template" msgid="3877037340223318119">"මුහුණු <xliff:g id="FACEID">%d</xliff:g>"</string> - <string name="face_app_setting_name" msgid="5854024256907828015">"මුහුණෙන් අගුළු ඇරීම භාවිත කර."</string> + <string name="face_app_setting_name" msgid="5854024256907828015">"මුහුණෙන් අගුළු හැරීම භාවිත කර."</string> <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"මුහුණෙන් අගුළු හැරීම හෝ තිර අගුල භාවිත කරන්න"</string> <string name="face_dialog_default_subtitle" msgid="6620492813371195429">"ඉදිරියට යාමට ඔබගේ මුහුණ භාවිත කරන්න"</string> <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"ඉදිරියට යාමට ඔබගේ මුහුණු හෝ තිර අගුල භාවිත කරන්න"</string> @@ -958,7 +958,7 @@ <string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"අගුළු නොදැමූ ප්රදේශය පුළුල් කරන්න."</string> <string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"සර්පණ අගුළු ඇරීම."</string> <string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"රටා අගුළු ඇරීම."</string> - <string name="keyguard_accessibility_face_unlock" msgid="4533832120787386728">"මුහුණෙන් අගුළු ඇරීම."</string> + <string name="keyguard_accessibility_face_unlock" msgid="4533832120787386728">"මුහුණෙන් අගුළු හැරීම."</string> <string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"PIN අගුළු ඇරීම."</string> <string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"Sim Pin අගුලු දැමීම."</string> <string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"Sim Puk අගුලු දැමීම."</string> diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml index 3d731e7ce84e..afdf1d9a4b21 100644 --- a/core/res/res/values-sk/strings.xml +++ b/core/res/res/values-sk/strings.xml @@ -26,7 +26,7 @@ <string name="gigabyteShort" msgid="7515809460261287991">"GB"</string> <string name="terabyteShort" msgid="1822367128583886496">"TB"</string> <string name="petabyteShort" msgid="5651571254228534832">"PB"</string> - <string name="fileSizeSuffix" msgid="4233671691980131257">"<xliff:g id="NUMBER">%1$s</xliff:g>&#160;<xliff:g id="UNIT">%2$s</xliff:g>"</string> + <string name="fileSizeSuffix" msgid="4233671691980131257">"<xliff:g id="NUMBER">%1$s</xliff:g>U+00A0<xliff:g id="UNIT">%2$s</xliff:g>"</string> <string name="untitled" msgid="3381766946944136678">"<Bez mena>"</string> <string name="emptyPhoneNumber" msgid="5812172618020360048">"(žiadne telefónne číslo)"</string> <string name="unknownName" msgid="7078697621109055330">"Bez názvu"</string> diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml index f7e81c79ee35..25e2820611f6 100644 --- a/core/res/res/values-sq/strings.xml +++ b/core/res/res/values-sq/strings.xml @@ -958,7 +958,7 @@ <string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Zgjero zonën e shkyçjes."</string> <string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Rrëshqit shkyçjen."</string> <string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Shkyçje me motiv."</string> - <string name="keyguard_accessibility_face_unlock" msgid="4533832120787386728">"Shkyçja me fytyrë"</string> + <string name="keyguard_accessibility_face_unlock" msgid="4533832120787386728">"Shkyçja me fytyrë."</string> <string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Shkyçje me PIN."</string> <string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"Shkyçja e kartës SIM me kodin PIN"</string> <string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"Shkyçja e kartës SIM me kodin PUK"</string> diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml index fcce9b479d52..18b588cd395c 100644 --- a/core/res/res/values-ta/strings.xml +++ b/core/res/res/values-ta/strings.xml @@ -1990,7 +1990,7 @@ <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="usb_mtp_launch_notification_description" msgid="6942535713629852684">"ஃபைல்களைப் பார்க்க, தட்டவும்"</string> <string name="pin_target" msgid="8036028973110156895">"பின் செய்"</string> <string name="pin_specific_target" msgid="7824671240625957415">"<xliff:g id="LABEL">%1$s</xliff:g> ஐப் பின் செய்"</string> <string name="unpin_target" msgid="3963318576590204447">"பின்னை அகற்று"</string> diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml index c57210e1d25b..1b4598add33a 100644 --- a/core/res/res/values-uk/strings.xml +++ b/core/res/res/values-uk/strings.xml @@ -1522,7 +1522,7 @@ <string name="deny" msgid="6632259981847676572">"Забор."</string> <string name="permission_request_notification_title" msgid="1810025922441048273">"Потрібен дозвіл"</string> <string name="permission_request_notification_with_subtitle" msgid="3743417870360129298">"Запитано дозвіл\nдля облікового запису <xliff:g id="ACCOUNT">%s</xliff:g>."</string> - <string name="permission_request_notification_for_app_with_subtitle" msgid="1298704005732851350">"Дозвіл, який додаток <xliff:g id="APP">%1$s</xliff:g> запитує\nна доступ до облікового запису <xliff:g id="ACCOUNT">%2$s</xliff:g>."</string> + <string name="permission_request_notification_for_app_with_subtitle" msgid="1298704005732851350">"Додаток <xliff:g id="APP">%1$s</xliff:g> запитує дозвіл\nна доступ до облікового запису <xliff:g id="ACCOUNT">%2$s</xliff:g>."</string> <string name="forward_intent_to_owner" msgid="4620359037192871015">"Ви використовуєте цей додаток за межами робочого профілю"</string> <string name="forward_intent_to_work" msgid="3620262405636021151">"Ви використовуєте цей додаток у своєму робочому профілі"</string> <string name="input_method_binding_label" msgid="1166731601721983656">"Метод введення"</string> diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml index 29303ba506fd..798e06c3f53c 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/strings.xml @@ -318,7 +318,7 @@ <string name="permgroupdesc_activityRecognition" msgid="4725624819457670704">"存取你的體能活動記錄"</string> <string name="permgrouplab_camera" msgid="9090413408963547706">"相機"</string> <string name="permgroupdesc_camera" msgid="7585150538459320326">"拍照及錄製影片"</string> - <string name="permgrouplab_nearby_devices" msgid="5529147543651181991">"附近的裝置"</string> + <string name="permgrouplab_nearby_devices" msgid="5529147543651181991">"鄰近裝置"</string> <string name="permgroupdesc_nearby_devices" msgid="3213561597116913508">"探索附近的裝置並進行連線"</string> <string name="permgrouplab_calllog" msgid="7926834372073550288">"通話記錄"</string> <string name="permgroupdesc_calllog" msgid="2026996642917801803">"讀取及寫入通話記錄"</string> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 546a28d5f34b..76fae85ca26a 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -4804,7 +4804,7 @@ <!-- Blur radius for the Option 3 in R.integer.config_letterboxBackgroundType. Values < 0 are ignored and 0 is used. --> - <dimen name="config_letterboxBackgroundWallpaperBlurRadius">100dp</dimen> + <dimen name="config_letterboxBackgroundWallpaperBlurRadius">31dp</dimen> <!-- Alpha of a black translucent scrim showed over wallpaper letterbox background when the Option 3 is selected for R.integer.config_letterboxBackgroundType. @@ -5041,4 +5041,7 @@ <!-- The default number of times per second that the seconds hand on AnalogClock ticks. If set to 0, the seconds hand will be disabled. --> <integer name="config_defaultAnalogClockSecondsHandFps">1</integer> + + <!-- the number of the max cached processes in the system. --> + <integer name="config_customizedMaxCachedProcesses">32</integer> </resources> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index bfd39a3c4234..40555fdaaa45 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -4423,4 +4423,6 @@ <java-symbol type="dimen" name="config_wallpaperDimAmount" /> <java-symbol type="bool" name="config_volumeShowRemoteSessions" /> + + <java-symbol type="integer" name="config_customizedMaxCachedProcesses" /> </resources> diff --git a/core/tests/coretests/src/android/content/pm/ConstrainDisplayApisConfigTest.java b/core/tests/coretests/src/android/content/pm/ConstrainDisplayApisConfigTest.java index 1dfbfcd85a73..0456029f45a0 100644 --- a/core/tests/coretests/src/android/content/pm/ConstrainDisplayApisConfigTest.java +++ b/core/tests/coretests/src/android/content/pm/ConstrainDisplayApisConfigTest.java @@ -48,7 +48,8 @@ public final class ConstrainDisplayApisConfigTest { public void setUp() throws Exception { mInitialConstrainDisplayApisFlags = DeviceConfig.getProperties( NAMESPACE_CONSTRAIN_DISPLAY_APIS); - clearConstrainDisplayApisFlags(); + DeviceConfig.setProperties( + new Properties.Builder(NAMESPACE_CONSTRAIN_DISPLAY_APIS).build()); } @After @@ -120,6 +121,29 @@ public final class ConstrainDisplayApisConfigTest { testNeverConstrainDisplayApis("com.android.test5", /* version= */ 5, /* expected= */ true); } + @Test + public void alwaysConstrainDisplayApis_flagsNoSet_returnsFalse() { + testAlwaysConstrainDisplayApis("com.android.test", /* version= */ 1, /* expected= */ false); + } + + @Test + public void alwaysConstrainDisplayApis_flagHasEntries_returnsTrueForPackagesWithinRange() { + setAlwaysConstrainDisplayApisFlag("com.android.test1::,com.android.test2:1:2"); + + // Package 'com.android.other' + testAlwaysConstrainDisplayApis("com.android.other", /* version= */ 5, /* expected= */ + false); + // Package 'com.android.test1' + testAlwaysConstrainDisplayApis("com.android.test1", /* version= */ 5, /* expected= */ true); + // Package 'com.android.test2' + testAlwaysConstrainDisplayApis("com.android.test2", /* version= */ 0, /* expected= */ + false); + testAlwaysConstrainDisplayApis("com.android.test2", /* version= */ 1, /* expected= */ true); + testAlwaysConstrainDisplayApis("com.android.test2", /* version= */ 2, /* expected= */ true); + testAlwaysConstrainDisplayApis("com.android.test2", /* version= */ 3, /* expected= */ + false); + } + private static void testNeverConstrainDisplayApis(String packageName, long version, boolean expected) { boolean result = ConstrainDisplayApisConfig.neverConstrainDisplayApis( @@ -131,6 +155,17 @@ public final class ConstrainDisplayApisConfigTest { } } + private static void testAlwaysConstrainDisplayApis(String packageName, long version, + boolean expected) { + boolean result = ConstrainDisplayApisConfig.alwaysConstrainDisplayApis( + buildApplicationInfo(packageName, version)); + if (expected) { + assertTrue(result); + } else { + assertFalse(result); + } + } + private static ApplicationInfo buildApplicationInfo(String packageName, long version) { ApplicationInfo applicationInfo = new ApplicationInfo(); applicationInfo.packageName = packageName; @@ -149,8 +184,8 @@ public final class ConstrainDisplayApisConfigTest { value, /* makeDefault= */ false); } - private static void clearConstrainDisplayApisFlags() { - setNeverConstrainDisplayApisFlag(null); - setNeverConstrainDisplayApisAllPackagesFlag(null); + private static void setAlwaysConstrainDisplayApisFlag(@Nullable String value) { + DeviceConfig.setProperty(NAMESPACE_CONSTRAIN_DISPLAY_APIS, "always_constrain_display_apis", + value, /* makeDefault= */ false); } } diff --git a/core/tests/coretests/src/android/window/WindowContextControllerTest.java b/core/tests/coretests/src/android/window/WindowContextControllerTest.java index 020f4a06b892..a6e351d9cee7 100644 --- a/core/tests/coretests/src/android/window/WindowContextControllerTest.java +++ b/core/tests/coretests/src/android/window/WindowContextControllerTest.java @@ -22,12 +22,15 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; 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.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doNothing; 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 android.content.res.Configuration; import android.os.Binder; import android.platform.test.annotations.Presubmit; import android.view.IWindowManager; @@ -38,6 +41,8 @@ import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; /** * Tests for {@link WindowContextController} @@ -53,15 +58,18 @@ import org.junit.runner.RunWith; @Presubmit public class WindowContextControllerTest { private WindowContextController mController; + @Mock private IWindowManager mMockWms; + @Mock + private WindowTokenClient mMockToken; @Before public void setUp() throws Exception { - mMockWms = mock(IWindowManager.class); - mController = new WindowContextController(new Binder(), mMockWms); - - doReturn(true).when(mMockWms).attachWindowContextToDisplayArea(any(), anyInt(), - anyInt(), any()); + MockitoAnnotations.initMocks(this); + mController = new WindowContextController(mMockToken, mMockWms); + doNothing().when(mMockToken).onConfigurationChanged(any(), anyInt(), anyBoolean()); + doReturn(new Configuration()).when(mMockWms).attachWindowContextToDisplayArea(any(), + anyInt(), anyInt(), any()); } @Test(expected = IllegalStateException.class) @@ -85,6 +93,8 @@ public class WindowContextControllerTest { null /* options */); assertThat(mController.mAttachedToDisplayArea).isTrue(); + verify(mMockToken).onConfigurationChanged(any(), eq(DEFAULT_DISPLAY), + eq(false) /* shouldReportConfigChange */); mController.detachIfNeeded(); diff --git a/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java b/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java index 4ef45e2b126b..b59b84bb15ba 100644 --- a/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java +++ b/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java @@ -580,11 +580,11 @@ public class BstatsCpuTimesValidationTest { final long[] cpuTimesMs4 = getAllCpuFreqTimes(sTestPkgUid, PROCESS_STATE_TOP); assertCpuTimesValid(cpuTimesMs4); actualCpuTimeMs = 0; - for (int i = 0; i < cpuTimesMs.length / 2; ++i) { - actualCpuTimeMs += cpuTimesMs[i]; + for (int i = 0; i < cpuTimesMs4.length / 2; ++i) { + actualCpuTimeMs += cpuTimesMs4[i]; } assertApproximateValue("Incorrect total cpu time, " + msgCpuTimes, - WORK_DURATION_MS, actualCpuTimeMs); + 2 * WORK_DURATION_MS, actualCpuTimeMs); batteryOffScreenOn(); } finally { diff --git a/core/tests/coretests/src/com/android/internal/statusbar/RegisterStatusBarResultTest.java b/core/tests/coretests/src/com/android/internal/statusbar/RegisterStatusBarResultTest.java index 272f2287dd6e..7d4412c7087d 100644 --- a/core/tests/coretests/src/com/android/internal/statusbar/RegisterStatusBarResultTest.java +++ b/core/tests/coretests/src/com/android/internal/statusbar/RegisterStatusBarResultTest.java @@ -24,6 +24,7 @@ import android.os.Binder; import android.os.Parcel; import android.os.UserHandle; import android.util.ArrayMap; +import android.view.InsetsState; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; @@ -59,7 +60,8 @@ public class RegisterStatusBarResultTest { new Binder() /* imeToken */, true /* navbarColorManagedByIme */, BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE, - true /* appFullscreen */, + new InsetsState() /* requestedState */, + "test" /* packageName */, new int[0] /* transientBarTypes */); final RegisterStatusBarResult copy = clone(original); @@ -79,7 +81,8 @@ public class RegisterStatusBarResultTest { assertThat(copy.mImeToken).isSameInstanceAs(original.mImeToken); assertThat(copy.mNavbarColorManagedByIme).isEqualTo(original.mNavbarColorManagedByIme); assertThat(copy.mBehavior).isEqualTo(original.mBehavior); - assertThat(copy.mAppFullscreen).isEqualTo(original.mAppFullscreen); + assertThat(copy.mRequestedState).isEqualTo(original.mRequestedState); + assertThat(copy.mPackageName).isEqualTo(original.mPackageName); assertThat(copy.mTransientBarTypes).isEqualTo(original.mTransientBarTypes); } diff --git a/data/etc/car/Android.bp b/data/etc/car/Android.bp index 084e1dbced4a..d1e4322ab612 100644 --- a/data/etc/car/Android.bp +++ b/data/etc/car/Android.bp @@ -130,6 +130,13 @@ prebuilt_etc { } prebuilt_etc { + name: "allowed_privapp_com.google.android.car.adaslocation", + sub_dir: "permissions", + src: "com.google.android.car.adaslocation.xml", + filename_from_src: true, +} + +prebuilt_etc { name: "allowed_privapp_com.google.android.car.kitchensink", sub_dir: "permissions", src: "com.google.android.car.kitchensink.xml", diff --git a/data/etc/car/com.google.android.car.adaslocation.xml b/data/etc/car/com.google.android.car.adaslocation.xml new file mode 100644 index 000000000000..cc1ef3c3e160 --- /dev/null +++ b/data/etc/car/com.google.android.car.adaslocation.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2021 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<permissions> + <privapp-permissions package="com.google.android.car.adaslocation"> + <permission name="android.permission.WRITE_SECURE_SETTINGS"/> + </privapp-permissions> +</permissions> diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml index 6385952fe884..813b7995fe89 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -315,6 +315,7 @@ applications that come with the platform <permission name="android.permission.INSTALL_DYNAMIC_SYSTEM"/> <permission name="android.permission.INSTALL_LOCATION_PROVIDER"/> <permission name="android.permission.INSTALL_PACKAGES"/> + <permission name="android.permission.INSTALL_PACKAGE_UPDATES"/> <!-- Needed for test only --> <permission name="android.permission.ACCESS_MTP"/> <!-- Needed for test only --> diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json index bfd12f8d76bc..50e6b90679b2 100644 --- a/data/etc/services.core.protolog.json +++ b/data/etc/services.core.protolog.json @@ -79,12 +79,6 @@ "group": "WM_DEBUG_WINDOW_TRANSITIONS", "at": "com\/android\/server\/wm\/Transition.java" }, - "-2029985709": { - "message": "setFocusedTask: taskId=%d", - "level": "DEBUG", - "group": "WM_DEBUG_FOCUS", - "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" - }, "-2024464438": { "message": "app-onAnimationFinished(): mOuter=%s", "level": "DEBUG", @@ -157,6 +151,12 @@ "group": "WM_DEBUG_ADD_REMOVE", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, + "-1963363332": { + "message": "Restart top activity process of Task taskId=%d", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_ORGANIZER", + "at": "com\/android\/server\/wm\/TaskOrganizerController.java" + }, "-1949279037": { "message": "Attempted to add input method window with bad token %s. Aborting.", "level": "WARN", @@ -169,12 +169,6 @@ "group": "WM_DEBUG_WINDOW_ORGANIZER", "at": "com\/android\/server\/wm\/TaskOrganizerController.java" }, - "-1939358269": { - "message": "mRecentScreenshotAnimator finish", - "level": "DEBUG", - "group": "WM_DEBUG_RECENTS_ANIMATIONS", - "at": "com\/android\/server\/wm\/RecentsAnimationController.java" - }, "-1938839202": { "message": "SURFACE LEAK DESTROY: %s", "level": "INFO", @@ -1783,6 +1777,12 @@ "group": "WM_DEBUG_STATES", "at": "com\/android\/server\/wm\/TaskFragment.java" }, + "-55185509": { + "message": "setFocusedTask: taskId=%d touchedActivity=%s", + "level": "DEBUG", + "group": "WM_DEBUG_FOCUS", + "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" + }, "-50336993": { "message": "moveFocusableActivityToTop: activity=%s", "level": "DEBUG", @@ -3535,12 +3535,6 @@ "group": "WM_DEBUG_APP_TRANSITIONS", "at": "com\/android\/server\/wm\/AppTransitionController.java" }, - "1984470582": { - "message": "Creating TaskScreenshotAnimatable: task: %s width: %d height: %d", - "level": "DEBUG", - "group": "WM_DEBUG_RECENTS_ANIMATIONS", - "at": "com\/android\/server\/wm\/TaskScreenshotAnimatable.java" - }, "1984782949": { "message": ">>> OPEN TRANSACTION animate", "level": "INFO", diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java index dc7f3dda35c0..7258a3af9e68 100644 --- a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java +++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java @@ -20,6 +20,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityThread; import android.content.Context; +import android.hardware.security.keymint.EcCurve; import android.hardware.security.keymint.KeyParameter; import android.hardware.security.keymint.KeyPurpose; import android.hardware.security.keymint.SecurityLevel; @@ -122,6 +123,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato new HashMap<String, Integer>(); private static final List<String> SUPPORTED_EC_NIST_CURVE_NAMES = new ArrayList<String>(); private static final List<Integer> SUPPORTED_EC_NIST_CURVE_SIZES = new ArrayList<Integer>(); + static { // Aliases for NIST P-224 SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-224", 224); @@ -175,12 +177,29 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato mOriginalKeymasterAlgorithm = keymasterAlgorithm; } + private @EcCurve int keySize2EcCurve(int keySizeBits) + throws InvalidAlgorithmParameterException { + switch (keySizeBits) { + case 224: + return EcCurve.P_224; + case 256: + return EcCurve.P_256; + case 384: + return EcCurve.P_384; + case 521: + return EcCurve.P_521; + default: + throw new InvalidAlgorithmParameterException( + "Unsupported EC curve keysize: " + keySizeBits); + } + } + @SuppressWarnings("deprecation") @Override public void initialize(int keysize, SecureRandom random) { throw new IllegalArgumentException( KeyGenParameterSpec.class.getName() + " or " + KeyPairGeneratorSpec.class.getName() - + " required to initialize this KeyPairGenerator"); + + " required to initialize this KeyPairGenerator"); } @SuppressWarnings("deprecation") @@ -194,7 +213,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato if (params == null) { throw new InvalidAlgorithmParameterException( "Must supply params of type " + KeyGenParameterSpec.class.getName() - + " or " + KeyPairGeneratorSpec.class.getName()); + + " or " + KeyPairGeneratorSpec.class.getName()); } KeyGenParameterSpec spec; @@ -215,8 +234,8 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato } else { throw new InvalidAlgorithmParameterException( "Unsupported params class: " + params.getClass().getName() - + ". Supported: " + KeyGenParameterSpec.class.getName() - + ", " + KeyPairGeneratorSpec.class.getName()); + + ". Supported: " + KeyGenParameterSpec.class.getName() + + ", " + KeyPairGeneratorSpec.class.getName()); } mEntryAlias = spec.getKeystoreAlias(); @@ -250,11 +269,11 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato keymasterPadding)) { throw new InvalidAlgorithmParameterException( "Randomized encryption (IND-CPA) required but may be violated" - + " by padding scheme: " - + KeyProperties.EncryptionPadding.fromKeymaster( + + " by padding scheme: " + + KeyProperties.EncryptionPadding.fromKeymaster( keymasterPadding) - + ". See " + KeyGenParameterSpec.class.getName() - + " documentation."); + + ". See " + KeyGenParameterSpec.class.getName() + + " documentation."); } } } @@ -378,7 +397,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato specBuilder = new KeyGenParameterSpec.Builder( legacySpec.getKeystoreAlias(), KeyProperties.PURPOSE_SIGN - | KeyProperties.PURPOSE_VERIFY); + | KeyProperties.PURPOSE_VERIFY); // Authorized to be used with any digest (including no digest). // MD5 was never offered for Android Keystore for ECDSA. specBuilder.setDigests( @@ -393,9 +412,9 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato specBuilder = new KeyGenParameterSpec.Builder( legacySpec.getKeystoreAlias(), KeyProperties.PURPOSE_ENCRYPT - | KeyProperties.PURPOSE_DECRYPT - | KeyProperties.PURPOSE_SIGN - | KeyProperties.PURPOSE_VERIFY); + | KeyProperties.PURPOSE_DECRYPT + | KeyProperties.PURPOSE_SIGN + | KeyProperties.PURPOSE_VERIFY); // Authorized to be used with any digest (including no digest). specBuilder.setDigests( KeyProperties.DIGEST_NONE, @@ -459,8 +478,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato private void initAlgorithmSpecificParameters() throws InvalidAlgorithmParameterException { AlgorithmParameterSpec algSpecificSpec = mSpec.getAlgorithmParameterSpec(); switch (mKeymasterAlgorithm) { - case KeymasterDefs.KM_ALGORITHM_RSA: - { + case KeymasterDefs.KM_ALGORITHM_RSA: { BigInteger publicExponent = null; if (algSpecificSpec instanceof RSAKeyGenParameterSpec) { RSAKeyGenParameterSpec rsaSpec = (RSAKeyGenParameterSpec) algSpecificSpec; @@ -474,7 +492,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato publicExponent = rsaSpec.getPublicExponent(); } else if (algSpecificSpec != null) { throw new InvalidAlgorithmParameterException( - "RSA may only use RSAKeyGenParameterSpec"); + "RSA may only use RSAKeyGenParameterSpec"); } if (publicExponent == null) { publicExponent = RSAKeyGenParameterSpec.F4; @@ -487,7 +505,8 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato || (publicExponent.compareTo(KeymasterArguments.UINT64_MAX_VALUE) > 0)) { throw new InvalidAlgorithmParameterException( "Unsupported RSA public exponent: " + publicExponent - + ". Maximum supported value: " + KeymasterArguments.UINT64_MAX_VALUE); + + ". Maximum supported value: " + + KeymasterArguments.UINT64_MAX_VALUE); } mRSAPublicExponent = publicExponent.longValue(); break; @@ -501,7 +520,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato if (ecSpecKeySizeBits == null) { throw new InvalidAlgorithmParameterException( "Unsupported EC curve name: " + curveName - + ". Supported: " + SUPPORTED_EC_NIST_CURVE_NAMES); + + ". Supported: " + SUPPORTED_EC_NIST_CURVE_NAMES); } if (mKeySizeBits == -1) { mKeySizeBits = ecSpecKeySizeBits; @@ -512,7 +531,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato } } else if (algSpecificSpec != null) { throw new InvalidAlgorithmParameterException( - "EC may only use ECGenParameterSpec"); + "EC may only use ECGenParameterSpec"); } break; default: @@ -546,7 +565,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato final int flags = mSpec.isCriticalToDeviceEncryption() ? IKeystoreSecurityLevel - .KEY_FLAG_AUTH_BOUND_WITHOUT_CRYPTOGRAPHIC_LSKF_BINDING + .KEY_FLAG_AUTH_BOUND_WITHOUT_CRYPTOGRAPHIC_LSKF_BINDING : 0; byte[] additionalEntropy = @@ -585,7 +604,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato success = true; return new KeyPair(publicKey, publicKey.getPrivateKey()); } catch (android.security.KeyStoreException e) { - switch(e.getErrorCode()) { + switch (e.getErrorCode()) { case KeymasterDefs.KM_ERROR_HARDWARE_TYPE_UNAVAILABLE: throw new StrongBoxUnavailableException("Failed to generated key pair.", e); case ResponseCode.OUT_OF_KEYS: @@ -605,7 +624,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato throw p; } } catch (UnrecoverableKeyException | IllegalArgumentException - | DeviceIdAttestationException e) { + | DeviceIdAttestationException | InvalidAlgorithmParameterException e) { throw new ProviderException( "Failed to construct key object from newly generated key pair.", e); } finally { @@ -666,8 +685,8 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato if (idTypesSet.contains(AttestationUtils.ID_TYPE_IMEI) || idTypesSet.contains(AttestationUtils.ID_TYPE_MEID)) { telephonyService = - (TelephonyManager) android.app.AppGlobals.getInitialApplication() - .getSystemService(Context.TELEPHONY_SERVICE); + (TelephonyManager) android.app.AppGlobals.getInitialApplication() + .getSystemService(Context.TELEPHONY_SERVICE); if (telephonyService == null) { throw new DeviceIdAttestationException("Unable to access telephony service"); } @@ -715,12 +734,20 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato } private Collection<KeyParameter> constructKeyGenerationArguments() - throws DeviceIdAttestationException, IllegalArgumentException { + throws DeviceIdAttestationException, IllegalArgumentException, + InvalidAlgorithmParameterException { List<KeyParameter> params = new ArrayList<>(); params.add(KeyStore2ParameterUtils.makeInt(KeymasterDefs.KM_TAG_KEY_SIZE, mKeySizeBits)); params.add(KeyStore2ParameterUtils.makeEnum( KeymasterDefs.KM_TAG_ALGORITHM, mKeymasterAlgorithm )); + + if (mKeymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_EC) { + params.add(KeyStore2ParameterUtils.makeEnum( + Tag.EC_CURVE, keySize2EcCurve(mKeySizeBits) + )); + } + ArrayUtils.forEach(mKeymasterPurposes, (purpose) -> { params.add(KeyStore2ParameterUtils.makeEnum( KeymasterDefs.KM_TAG_PURPOSE, purpose @@ -844,7 +871,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato if (isStrongBoxBacked && keySize != 256) { throw new InvalidAlgorithmParameterException( "Unsupported StrongBox EC key size: " - + keySize + " bits. Supported: 256"); + + keySize + " bits. Supported: 256"); } if (!SUPPORTED_EC_NIST_CURVE_SIZES.contains(keySize)) { throw new InvalidAlgorithmParameterException("Unsupported EC key size: " @@ -892,8 +919,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato return null; } switch (keymasterAlgorithm) { - case KeymasterDefs.KM_ALGORITHM_EC: - { + case KeymasterDefs.KM_ALGORITHM_EC: { Set<Integer> availableKeymasterDigests = getAvailableKeymasterSignatureDigests( spec.getDigests(), AndroidKeyStoreBCWorkaroundProvider.getSupportedEcdsaSignatureDigests()); @@ -940,8 +966,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato return KeyProperties.Digest.fromKeymasterToSignatureAlgorithmDigest( bestKeymasterDigest) + "WithECDSA"; } - case KeymasterDefs.KM_ALGORITHM_RSA: - { + case KeymasterDefs.KM_ALGORITHM_RSA: { // Check whether this key is authorized for PKCS#1 signature padding. // We use Bouncy Castle to generate self-signed RSA certificates. Bouncy Castle // only supports RSA certificates signed using PKCS#1 padding scheme. The key needs diff --git a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml index 0af8d24a1783..aa666531996d 100644 --- a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml +++ b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml @@ -46,7 +46,7 @@ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"以 30% 的螢幕空間顯示頂端畫面"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"以全螢幕顯示底部畫面"</string> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"使用單手模式"</string> - <string name="one_handed_tutorial_description" msgid="3486582858591353067">"如要退出,請從螢幕底部向上滑動,或輕觸應用程式上的任何位置"</string> + <string name="one_handed_tutorial_description" msgid="3486582858591353067">"如要退出,請從螢幕底部向上滑動,或輕觸應用程式上方的任何位置"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"啟動單手模式"</string> <string name="accessibility_action_stop_one_handed" msgid="1369940261782179442">"結束單手模式"</string> <string name="bubbles_settings_button_description" msgid="1301286017420516912">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」對話框的設定"</string> diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java index 0b941b59b3db..9113c79d40f8 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java @@ -103,6 +103,8 @@ public final class ShellCommandHandlerImpl { return runMoveToSideStage(args, pw); case "removeFromSideStage": return runRemoveFromSideStage(args, pw); + case "setSideStageOutline": + return runSetSideStageOutline(args, pw); case "setSideStagePosition": return runSetSideStagePosition(args, pw); case "setSideStageVisibility": @@ -161,6 +163,18 @@ public final class ShellCommandHandlerImpl { return true; } + private boolean runSetSideStageOutline(String[] args, PrintWriter pw) { + if (args.length < 3) { + // First arguments are "WMShell" and command name. + pw.println("Error: whether to enable or disable side stage outline border should be" + + " provided as arguments"); + return false; + } + final boolean enable = new Boolean(args[2]); + mSplitScreenOptional.ifPresent(split -> split.setSideStageOutline(enable)); + return true; + } + private boolean runSetSideStagePosition(String[] args, PrintWriter pw) { if (args.length < 3) { // First arguments are "WMShell" and command name. @@ -175,7 +189,7 @@ public final class ShellCommandHandlerImpl { private boolean runSetSideStageVisibility(String[] args, PrintWriter pw) { if (args.length < 3) { // First arguments are "WMShell" and command name. - pw.println("Error: side stage position should be provided as arguments"); + pw.println("Error: side stage visibility should be provided as arguments"); return false; } final Boolean visible = new Boolean(args[2]); @@ -197,6 +211,8 @@ public final class ShellCommandHandlerImpl { pw.println(" Move a task with given id in split-screen mode."); pw.println(" removeFromSideStage <taskId>"); pw.println(" Remove a task with given id in split-screen mode."); + pw.println(" setSideStageOutline <true/false>"); + pw.println(" Enable/Disable outline on the side-stage."); pw.println(" setSideStagePosition <SideStagePosition>"); pw.println(" Sets the position of the side-stage."); pw.println(" setSideStageVisibility <true/false>"); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java index 4b1955e56a6c..ba0ab6db1003 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java @@ -62,7 +62,8 @@ import java.util.function.Consumer; * Unified task organizer for all components in the shell. * TODO(b/167582004): may consider consolidating this class and TaskOrganizer */ -public class ShellTaskOrganizer extends TaskOrganizer { +public class ShellTaskOrganizer extends TaskOrganizer implements + SizeCompatUIController.SizeCompatUICallback { // Intentionally using negative numbers here so the positive numbers can be used // for task id specific listeners that will be added later. @@ -158,6 +159,9 @@ public class ShellTaskOrganizer extends TaskOrganizer { Context context, @Nullable SizeCompatUIController sizeCompatUI) { super(taskOrganizerController, mainExecutor); mSizeCompatUI = sizeCompatUI; + if (sizeCompatUI != null) { + sizeCompatUI.setSizeCompatUICallback(this); + } } @Override @@ -481,6 +485,17 @@ public class ShellTaskOrganizer extends TaskOrganizer { } } + @Override + public void onSizeCompatRestartButtonClicked(int taskId) { + final TaskAppearedInfo info; + synchronized (mLock) { + info = mTasks.get(taskId); + } + if (info != null) { + restartTaskTopActivityProcessIfVisible(info.getTaskInfo().token); + } + } + /** * Notifies {@link SizeCompatUIController} about the size compat info changed on the give Task * to update the UI accordingly. @@ -497,15 +512,14 @@ public class ShellTaskOrganizer extends TaskOrganizer { // The task is vanished or doesn't support size compat UI, notify to remove size compat UI // on this Task if there is any. if (taskListener == null || !taskListener.supportSizeCompatUI() - || !taskInfo.topActivityInSizeCompat) { + || !taskInfo.topActivityInSizeCompat || !taskInfo.isVisible) { mSizeCompatUI.onSizeCompatInfoChanged(taskInfo.displayId, taskInfo.taskId, - null /* taskConfig */, null /* sizeCompatActivity*/, - null /* taskListener */); + null /* taskConfig */, null /* taskListener */); return; } mSizeCompatUI.onSizeCompatInfoChanged(taskInfo.displayId, taskInfo.taskId, - taskInfo.configuration, taskInfo.topActivityToken, taskListener); + taskInfo.configuration, taskListener); } private TaskListener getTaskListener(RunningTaskInfo runningTaskInfo) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java index ef113dc5e10a..97c89d042be0 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java @@ -134,6 +134,18 @@ public class SystemWindows { } /** + * Sets the accessibility window for the given {@param shellRootLayer}. + */ + public void setShellRootAccessibilityWindow(int displayId, + @WindowManager.ShellRootLayer int shellRootLayer, View view) { + PerDisplay pd = mPerDisplay.get(displayId); + if (pd == null) { + return; + } + pd.setShellRootAccessibilityWindow(shellRootLayer, view); + } + + /** * Sets the touchable region of a view's window. This will be cropped to the window size. * @param view * @param region @@ -202,15 +214,9 @@ public class SystemWindows { attrs.flags |= FLAG_HARDWARE_ACCELERATED; viewRoot.setView(view, attrs); mViewRoots.put(view, viewRoot); - - try { - mWmService.setShellRootAccessibilityWindow(mDisplayId, shellRootLayer, - viewRoot.getWindowToken()); - } catch (RemoteException e) { - Slog.e(TAG, "Error setting accessibility window for " + mDisplayId + ":" - + shellRootLayer, e); - } + setShellRootAccessibilityWindow(shellRootLayer, view); } + SysUiWindowManager addRoot(@WindowManager.ShellRootLayer int shellRootLayer) { SysUiWindowManager wwm = mWwms.get(shellRootLayer); if (wwm != null) { @@ -240,6 +246,21 @@ public class SystemWindows { return wwm.mContainerWindow; } + void setShellRootAccessibilityWindow(@WindowManager.ShellRootLayer int shellRootLayer, + View view) { + SysUiWindowManager wwm = mWwms.get(shellRootLayer); + if (wwm == null) { + return; + } + try { + mWmService.setShellRootAccessibilityWindow(mDisplayId, shellRootLayer, + view != null ? mViewRoots.get(view).getWindowToken() : null); + } catch (RemoteException e) { + Slog.e(TAG, "Error setting accessibility window for " + mDisplayId + ":" + + shellRootLayer, e); + } + } + void updateConfiguration(Configuration configuration) { for (int i = 0; i < mWwms.size(); ++i) { mWwms.valueAt(i).updateConfiguration(configuration); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java index 1cc7ed3afcf7..2038cff4a966 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java @@ -43,7 +43,6 @@ import android.util.Slog; import android.view.Surface; import android.view.WindowManager; import android.view.accessibility.AccessibilityManager; -import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -79,6 +78,7 @@ public class OneHandedController implements RemoteCallable<OneHandedController> private volatile boolean mIsOneHandedEnabled; private volatile boolean mIsSwipeToNotificationEnabled; + private boolean mIsShortcutEnabled; private boolean mTaskChangeToExit; private boolean mLockedDisabled; private boolean mKeyguardShowing; @@ -140,9 +140,8 @@ public class OneHandedController implements RemoteCallable<OneHandedController> private final ContentObserver mActivatedObserver; private final ContentObserver mEnabledObserver; - private final ContentObserver mTimeoutObserver; - private final ContentObserver mTaskChangeExitObserver; private final ContentObserver mSwipeToNotificationEnabledObserver; + private final ContentObserver mShortcutEnabledObserver; private AccessibilityManager.AccessibilityStateChangeListener mAccessibilityStateChangeListener = @@ -174,13 +173,13 @@ public class OneHandedController implements RemoteCallable<OneHandedController> @Override public void onStartFinished(Rect bounds) { mState.setState(STATE_ACTIVE); - notifyShortcutState(STATE_ACTIVE); + notifyShortcutStateChanged(STATE_ACTIVE); } @Override public void onStopFinished(Rect bounds) { mState.setState(STATE_NONE); - notifyShortcutState(STATE_NONE); + notifyShortcutStateChanged(STATE_NONE); } }; @@ -224,7 +223,7 @@ public class OneHandedController implements RemoteCallable<OneHandedController> OneHandedTimeoutHandler timeoutHandler = new OneHandedTimeoutHandler(mainExecutor); OneHandedState transitionState = new OneHandedState(); OneHandedTutorialHandler tutorialHandler = new OneHandedTutorialHandler(context, - displayLayout, windowManager, settingsUtil, mainExecutor); + windowManager); OneHandedAnimationController animationController = new OneHandedAnimationController(context); OneHandedTouchHandler touchHandler = new OneHandedTouchHandler(timeoutHandler, @@ -291,10 +290,9 @@ public class OneHandedController implements RemoteCallable<OneHandedController> mActivatedObserver = getObserver(this::onActivatedActionChanged); mEnabledObserver = getObserver(this::onEnabledSettingChanged); - mTimeoutObserver = getObserver(this::onTimeoutSettingChanged); - mTaskChangeExitObserver = getObserver(this::onTaskChangeExitSettingChanged); mSwipeToNotificationEnabledObserver = getObserver(this::onSwipeToNotificationEnabledChanged); + mShortcutEnabledObserver = getObserver(this::onShortcutEnabledChanged); mDisplayController.addDisplayChangingController(mRotationController); setupCallback(); @@ -349,11 +347,13 @@ public class OneHandedController implements RemoteCallable<OneHandedController> */ void setSwipeToNotificationEnabled(boolean enabled) { mIsSwipeToNotificationEnabled = enabled; - updateOneHandedEnabled(); } @VisibleForTesting - void notifyShortcutState(@OneHandedState.State int state) { + void notifyShortcutStateChanged(@OneHandedState.State int state) { + if (!isShortcutEnabled()) { + return; + } mOneHandedSettingsUtil.setOneHandedModeActivated( mContext.getContentResolver(), state == STATE_ACTIVE ? 1 : 0, mUserId); } @@ -436,24 +436,21 @@ public class OneHandedController implements RemoteCallable<OneHandedController> mContext.getContentResolver(), mActivatedObserver, newUserId); mOneHandedSettingsUtil.registerSettingsKeyObserver(Settings.Secure.ONE_HANDED_MODE_ENABLED, mContext.getContentResolver(), mEnabledObserver, newUserId); - mOneHandedSettingsUtil.registerSettingsKeyObserver(Settings.Secure.ONE_HANDED_MODE_TIMEOUT, - mContext.getContentResolver(), mTimeoutObserver, newUserId); - mOneHandedSettingsUtil.registerSettingsKeyObserver(Settings.Secure.TAPS_APP_TO_EXIT, - mContext.getContentResolver(), mTaskChangeExitObserver, newUserId); mOneHandedSettingsUtil.registerSettingsKeyObserver( Settings.Secure.SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED, mContext.getContentResolver(), mSwipeToNotificationEnabledObserver, newUserId); + mOneHandedSettingsUtil.registerSettingsKeyObserver( + Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, + mContext.getContentResolver(), mShortcutEnabledObserver, newUserId); } private void unregisterSettingObservers() { mOneHandedSettingsUtil.unregisterSettingsKeyObserver(mContext.getContentResolver(), mEnabledObserver); mOneHandedSettingsUtil.unregisterSettingsKeyObserver(mContext.getContentResolver(), - mTimeoutObserver); - mOneHandedSettingsUtil.unregisterSettingsKeyObserver(mContext.getContentResolver(), - mTaskChangeExitObserver); - mOneHandedSettingsUtil.unregisterSettingsKeyObserver(mContext.getContentResolver(), mSwipeToNotificationEnabledObserver); + mOneHandedSettingsUtil.unregisterSettingsKeyObserver(mContext.getContentResolver(), + mShortcutEnabledObserver); } private void updateSettings() { @@ -465,6 +462,7 @@ public class OneHandedController implements RemoteCallable<OneHandedController> .getSettingsTapsAppToExit(mContext.getContentResolver(), mUserId)); setSwipeToNotificationEnabled(mOneHandedSettingsUtil .getSettingsSwipeToNotificationEnabled(mContext.getContentResolver(), mUserId)); + onShortcutEnabledChanged(); } private void updateDisplayLayout(int displayId) { @@ -490,15 +488,6 @@ public class OneHandedController implements RemoteCallable<OneHandedController> } @VisibleForTesting - void notifyUserConfigChanged(boolean success) { - if (!success) { - return; - } - // TODO Check UX if popup Toast to notify user when auto-enabled one-handed is good option. - Toast.makeText(mContext, R.string.one_handed_tutorial_title, Toast.LENGTH_LONG).show(); - } - - @VisibleForTesting void onActivatedActionChanged() { if (!isShortcutEnabled()) { Slog.w(TAG, "Shortcut not enabled, skip onActivatedActionChanged()"); @@ -508,7 +497,7 @@ public class OneHandedController implements RemoteCallable<OneHandedController> if (!isOneHandedEnabled()) { final boolean success = mOneHandedSettingsUtil.setOneHandedModeEnabled( mContext.getContentResolver(), 1 /* Enabled for shortcut */, mUserId); - notifyUserConfigChanged(success); + Slog.d(TAG, "Auto enabled One-handed mode by shortcut trigger, success=" + success); } if (isSwipeToNotificationEnabled()) { @@ -547,46 +536,6 @@ public class OneHandedController implements RemoteCallable<OneHandedController> } @VisibleForTesting - void onTimeoutSettingChanged() { - final int newTimeout = mOneHandedSettingsUtil.getSettingsOneHandedModeTimeout( - mContext.getContentResolver(), mUserId); - int metricsId = OneHandedUiEventLogger.OneHandedSettingsTogglesEvent.INVALID.getId(); - switch (newTimeout) { - case OneHandedSettingsUtil.ONE_HANDED_TIMEOUT_NEVER: - metricsId = OneHandedUiEventLogger.EVENT_ONE_HANDED_SETTINGS_TIMEOUT_SECONDS_NEVER; - break; - case OneHandedSettingsUtil.ONE_HANDED_TIMEOUT_SHORT_IN_SECONDS: - metricsId = OneHandedUiEventLogger.EVENT_ONE_HANDED_SETTINGS_TIMEOUT_SECONDS_4; - break; - case OneHandedSettingsUtil.ONE_HANDED_TIMEOUT_MEDIUM_IN_SECONDS: - metricsId = OneHandedUiEventLogger.EVENT_ONE_HANDED_SETTINGS_TIMEOUT_SECONDS_8; - break; - case OneHandedSettingsUtil.ONE_HANDED_TIMEOUT_LONG_IN_SECONDS: - metricsId = OneHandedUiEventLogger.EVENT_ONE_HANDED_SETTINGS_TIMEOUT_SECONDS_12; - break; - default: - // do nothing - break; - } - mOneHandedUiEventLogger.writeEvent(metricsId); - - if (mTimeoutHandler != null) { - mTimeoutHandler.setTimeout(newTimeout); - } - } - - @VisibleForTesting - void onTaskChangeExitSettingChanged() { - final boolean enabled = mOneHandedSettingsUtil.getSettingsTapsAppToExit( - mContext.getContentResolver(), mUserId); - mOneHandedUiEventLogger.writeEvent(enabled - ? OneHandedUiEventLogger.EVENT_ONE_HANDED_SETTINGS_APP_TAPS_EXIT_ON - : OneHandedUiEventLogger.EVENT_ONE_HANDED_SETTINGS_APP_TAPS_EXIT_OFF); - - setTaskChangeToExit(enabled); - } - - @VisibleForTesting void onSwipeToNotificationEnabledChanged() { final boolean enabled = mOneHandedSettingsUtil.getSettingsSwipeToNotificationEnabled( @@ -596,11 +545,15 @@ public class OneHandedController implements RemoteCallable<OneHandedController> mOneHandedUiEventLogger.writeEvent(enabled ? OneHandedUiEventLogger.EVENT_ONE_HANDED_SETTINGS_SHOW_NOTIFICATION_ENABLED_ON : OneHandedUiEventLogger.EVENT_ONE_HANDED_SETTINGS_SHOW_NOTIFICATION_ENABLED_OFF); + } - // Also checks one handed mode settings since they all need gesture overlay. - setEnabledGesturalOverlay( - enabled || mOneHandedSettingsUtil.getSettingsOneHandedModeEnabled( - mContext.getContentResolver(), mUserId), true /* DelayExecute */); + void onShortcutEnabledChanged() { + mIsShortcutEnabled = mOneHandedSettingsUtil.getShortcutEnabled( + mContext.getContentResolver(), mUserId); + + mOneHandedUiEventLogger.writeEvent(mIsShortcutEnabled + ? OneHandedUiEventLogger.EVENT_ONE_HANDED_SETTINGS_SHORTCUT_ENABLED_ON + : OneHandedUiEventLogger.EVENT_ONE_HANDED_SETTINGS_SHORTCUT_ENABLED_OFF); } private void setupTimeoutListener() { @@ -620,7 +573,7 @@ public class OneHandedController implements RemoteCallable<OneHandedController> @VisibleForTesting boolean isShortcutEnabled() { - return mOneHandedSettingsUtil.getShortcutEnabled(mContext.getContentResolver(), mUserId); + return mIsShortcutEnabled; } @VisibleForTesting @@ -634,9 +587,9 @@ public class OneHandedController implements RemoteCallable<OneHandedController> } // If setting is pull screen, notify shortcut one_handed_mode_activated to reset - // and align status with current mState when function enabled. + // and align status with current mState when one-handed gesture enabled. if (isOneHandedEnabled() && !isSwipeToNotificationEnabled()) { - notifyShortcutState(mState.getState()); + notifyShortcutStateChanged(mState.getState()); } mTouchHandler.onOneHandedEnabled(mIsOneHandedEnabled); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java index 3baa69f0033a..5911f8d66b32 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java @@ -23,6 +23,7 @@ import android.content.ContentResolver; import android.database.ContentObserver; import android.net.Uri; import android.provider.Settings; +import android.text.TextUtils; import androidx.annotation.Nullable; @@ -170,7 +171,7 @@ public final class OneHandedSettingsUtil { public boolean getShortcutEnabled(ContentResolver resolver, int userId) { final String targets = Settings.Secure.getStringForUser(resolver, Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, userId); - return targets != null ? targets.contains(ONE_HANDED_MODE_TARGET_NAME) : false; + return TextUtils.isEmpty(targets) ? false : targets.contains(ONE_HANDED_MODE_TARGET_NAME); } /** diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java index 6cee404758ec..0f6c4b081cb7 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java @@ -16,7 +16,7 @@ package com.android.wm.shell.onehanded; -import static android.os.UserHandle.myUserId; +import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; import static com.android.wm.shell.onehanded.OneHandedState.STATE_ACTIVE; import static com.android.wm.shell.onehanded.OneHandedState.STATE_ENTERING; @@ -24,7 +24,6 @@ import static com.android.wm.shell.onehanded.OneHandedState.STATE_EXITING; import static com.android.wm.shell.onehanded.OneHandedState.STATE_NONE; import android.annotation.Nullable; -import android.content.ContentResolver; import android.content.Context; import android.graphics.PixelFormat; import android.graphics.Rect; @@ -41,7 +40,6 @@ import androidx.annotation.NonNull; import com.android.internal.annotations.VisibleForTesting; import com.android.wm.shell.R; import com.android.wm.shell.common.DisplayLayout; -import com.android.wm.shell.common.ShellExecutor; import java.io.PrintWriter; @@ -56,57 +54,44 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback, private static final String TAG = "OneHandedTutorialHandler"; private static final String ONE_HANDED_MODE_OFFSET_PERCENTAGE = "persist.debug.one_handed_offset_percentage"; - private static final int MAX_TUTORIAL_SHOW_COUNT = 2; private final float mTutorialHeightRatio; private final WindowManager mWindowManager; - private final OneHandedSettingsUtil mSettingsUtil; - private final ShellExecutor mShellExecutor; - private boolean mCanShow; + private boolean mIsShowing; private @OneHandedState.State int mCurrentState; - private int mShownCounts; private int mTutorialAreaHeight; private Context mContext; - private ContentResolver mContentResolver; private Rect mDisplayBounds; private @Nullable View mTutorialView; private @Nullable ViewGroup mTargetViewContainer; - private final OneHandedAnimationCallback mAnimationCallback = new OneHandedAnimationCallback() { - @Override - public void onAnimationUpdate(float xPos, float yPos) { - if (!canShowTutorial()) { - return; - } - mTargetViewContainer.setTransitionGroup(true); - mTargetViewContainer.setTranslationY(yPos - mTargetViewContainer.getHeight()); - } - }; + private final OneHandedAnimationCallback mAnimationCallback; - public OneHandedTutorialHandler(Context context, DisplayLayout displayLayout, - WindowManager windowManager, OneHandedSettingsUtil settingsUtil, - ShellExecutor mainExecutor) { + public OneHandedTutorialHandler(Context context, WindowManager windowManager) { mContext = context; - mContentResolver = context.getContentResolver(); mWindowManager = windowManager; - mSettingsUtil = settingsUtil; - mShellExecutor = mainExecutor; final float offsetPercentageConfig = context.getResources().getFraction( R.fraction.config_one_handed_offset, 1, 1); final int sysPropPercentageConfig = SystemProperties.getInt( ONE_HANDED_MODE_OFFSET_PERCENTAGE, Math.round(offsetPercentageConfig * 100.0f)); mTutorialHeightRatio = sysPropPercentageConfig / 100.0f; - mShownCounts = mSettingsUtil.getTutorialShownCounts(mContentResolver, myUserId()); + mAnimationCallback = new OneHandedAnimationCallback() { + @Override + public void onAnimationUpdate(float xPos, float yPos) { + if (!isShowing()) { + return; + } + mTargetViewContainer.setTransitionGroup(true); + mTargetViewContainer.setTranslationY(yPos - mTargetViewContainer.getHeight()); + } + }; } @Override public void onStateChanged(int newState) { mCurrentState = newState; - if (!canShowTutorial()) { - return; - } switch (newState) { case STATE_ENTERING: createViewAndAttachToWindow(mContext); @@ -139,7 +124,7 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback, @VisibleForTesting void createViewAndAttachToWindow(Context context) { - if (!canShowTutorial()) { + if (isShowing()) { return; } mTutorialView = LayoutInflater.from(context).inflate(R.layout.one_handed_tutorial, null); @@ -150,15 +135,6 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback, attachTargetToWindow(); } - @VisibleForTesting - boolean setTutorialShownCountIncrement() { - if (!canShowTutorial()) { - return false; - } - mShownCounts += 1; - return mSettingsUtil.setTutorialShownCounts(mContentResolver, mShownCounts, myUserId()); - } - /** * Adds the tutorial target view to the WindowManager and update its layout. */ @@ -166,6 +142,7 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback, if (!mTargetViewContainer.isAttachedToWindow()) { try { mWindowManager.addView(mTargetViewContainer, getTutorialTargetLayoutParams()); + mIsShowing = true; } catch (IllegalStateException e) { // This shouldn't happen, but if the target is already added, just update its // layout params. @@ -179,14 +156,12 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback, void removeTutorialFromWindowManager(boolean increment) { if (mTargetViewContainer != null && mTargetViewContainer.isAttachedToWindow()) { mWindowManager.removeViewImmediate(mTargetViewContainer); - if (increment) { - setTutorialShownCountIncrement(); - } + mIsShowing = false; } } @Nullable OneHandedAnimationCallback getAnimationCallback() { - return canShowTutorial() ? mAnimationCallback : null /* Disabled */; + return isShowing() ? mAnimationCallback : null /* Disabled */; } /** @@ -200,6 +175,7 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback, | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT); lp.gravity = Gravity.TOP | Gravity.LEFT; + lp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; lp.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS; lp.setFitInsetsTypes(0 /* types */); lp.setTitle("one-handed-tutorial-overlay"); @@ -207,17 +183,14 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback, } @VisibleForTesting - boolean canShowTutorial() { - return mCanShow = mShownCounts < MAX_TUTORIAL_SHOW_COUNT; + boolean isShowing() { + return mIsShowing; } /** * onConfigurationChanged events for updating tutorial text. */ public void onConfigurationChanged() { - if (!canShowTutorial()) { - return; - } removeTutorialFromWindowManager(false /* increment */); if (mCurrentState == STATE_ENTERING || mCurrentState == STATE_ACTIVE) { createViewAndAttachToWindow(mContext); @@ -227,14 +200,12 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback, void dump(@NonNull PrintWriter pw) { final String innerPrefix = " "; pw.println(TAG); - pw.print(innerPrefix + "mCanShow="); - pw.println(mCanShow); + pw.print(innerPrefix + "mIsShowing="); + pw.println(mIsShowing); pw.print(innerPrefix + "mCurrentState="); pw.println(mCurrentState); pw.print(innerPrefix + "mDisplayBounds="); pw.println(mDisplayBounds); - pw.print(innerPrefix + "mShownCounts="); - pw.println(mShownCounts); pw.print(innerPrefix + "mTutorialAreaHeight="); pw.println(mTutorialAreaHeight); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedUiEventLogger.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedUiEventLogger.java index 4e610fad05ae..1cf408075c9d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedUiEventLogger.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedUiEventLogger.java @@ -52,6 +52,8 @@ public class OneHandedUiEventLogger { public static final int EVENT_ONE_HANDED_SETTINGS_TIMEOUT_SECONDS_12 = 17; public static final int EVENT_ONE_HANDED_SETTINGS_SHOW_NOTIFICATION_ENABLED_ON = 18; public static final int EVENT_ONE_HANDED_SETTINGS_SHOW_NOTIFICATION_ENABLED_OFF = 19; + public static final int EVENT_ONE_HANDED_SETTINGS_SHORTCUT_ENABLED_ON = 20; + public static final int EVENT_ONE_HANDED_SETTINGS_SHORTCUT_ENABLED_OFF = 21; private static final String[] EVENT_TAGS = { "one_handed_trigger_gesture_in", @@ -73,7 +75,9 @@ public class OneHandedUiEventLogger { "one_handed_settings_timeout_seconds_8", "one_handed_settings_timeout_seconds_12", "one_handed_settings_show_notification_enabled_on", - "one_handed_settings_show_notification_enabled_off" + "one_handed_settings_show_notification_enabled_off", + "one_handed_settings_shortcut_enabled_on", + "one_handed_settings_shortcut_enabled_off" }; public OneHandedUiEventLogger(UiEventLogger uiEventLogger) { @@ -162,7 +166,13 @@ public class OneHandedUiEventLogger { ONE_HANDED_SETTINGS_TOGGLES_SHOW_NOTIFICATION_ENABLED_ON(847), @UiEvent(doc = "One-Handed mode show notification toggle off") - ONE_HANDED_SETTINGS_TOGGLES_SHOW_NOTIFICATION_ENABLED_OFF(848); + ONE_HANDED_SETTINGS_TOGGLES_SHOW_NOTIFICATION_ENABLED_OFF(848), + + @UiEvent(doc = "One-Handed mode shortcut toggle on") + ONE_HANDED_SETTINGS_TOGGLES_SHORTCUT_ENABLED_ON(870), + + @UiEvent(doc = "One-Handed mode shortcut toggle off") + ONE_HANDED_SETTINGS_TOGGLES_SHORTCUT_ENABLED_OFF(871); private final int mId; @@ -265,6 +275,14 @@ public class OneHandedUiEventLogger { mUiEventLogger.log(OneHandedSettingsTogglesEvent .ONE_HANDED_SETTINGS_TOGGLES_SHOW_NOTIFICATION_ENABLED_OFF); break; + case EVENT_ONE_HANDED_SETTINGS_SHORTCUT_ENABLED_ON: + mUiEventLogger.log(OneHandedSettingsTogglesEvent + .ONE_HANDED_SETTINGS_TOGGLES_SHORTCUT_ENABLED_ON); + break; + case EVENT_ONE_HANDED_SETTINGS_SHORTCUT_ENABLED_OFF: + mUiEventLogger.log(OneHandedSettingsTogglesEvent + .ONE_HANDED_SETTINGS_TOGGLES_SHORTCUT_ENABLED_OFF); + break; default: // Do nothing break; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java index efff3e30f010..6c3576b438b1 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java @@ -614,6 +614,12 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, } private void onEndOfSwipePipToHomeTransition() { + if (Transitions.ENABLE_SHELL_TRANSITIONS) { + mInSwipePipToHomeTransition = false; + mSwipePipToHomeOverlay = null; + return; + } + final Rect destinationBounds = mPipBoundsState.getBounds(); final SurfaceControl swipeToHomeOverlay = mSwipePipToHomeOverlay; final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction(); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java index b75cde099bcb..18153e3f4246 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java @@ -32,6 +32,7 @@ import static com.android.wm.shell.transition.Transitions.TRANSIT_REMOVE_PIP; import android.app.TaskInfo; import android.content.Context; +import android.graphics.Matrix; import android.graphics.Rect; import android.os.IBinder; import android.view.Surface; @@ -214,6 +215,25 @@ public class PipTransition extends PipTransitionController { final Rect currentBounds = taskInfo.configuration.windowConfiguration.getBounds(); PipAnimationController.PipTransitionAnimator animator; finishTransaction.setPosition(leash, destinationBounds.left, destinationBounds.top); + if (taskInfo.pictureInPictureParams != null + && taskInfo.pictureInPictureParams.isAutoEnterEnabled()) { + mOneShotAnimationType = ANIM_TYPE_BOUNDS; + + // PiP menu is attached late in the process here to avoid any artifacts on the leash + // caused by addShellRoot when in gesture navigation mode. + mPipMenuController.attach(leash); + SurfaceControl.Transaction tx = new SurfaceControl.Transaction(); + tx.setMatrix(leash, Matrix.IDENTITY_MATRIX, new float[9]) + .setPosition(leash, destinationBounds.left, destinationBounds.top) + .setWindowCrop(leash, destinationBounds.width(), destinationBounds.height()); + startTransaction.merge(tx); + startTransaction.apply(); + mPipBoundsState.setBounds(destinationBounds); + onFinishResize(taskInfo, destinationBounds, TRANSITION_DIRECTION_TO_PIP, tx); + sendOnPipTransitionFinished(TRANSITION_DIRECTION_TO_PIP); + mFinishCallback = null; + return true; + } if (mOneShotAnimationType == ANIM_TYPE_BOUNDS) { final Rect sourceHintRect = PipBoundsAlgorithm.getValidSourceHintRect( diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java index bc8e1e72b830..a646b07c49dc 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java @@ -524,6 +524,15 @@ public class PhonePipMenuController implements PipMenuController { mListeners.forEach(l -> l.onPipMenuStateChangeFinish(menuState)); } mMenuState = menuState; + switch (mMenuState) { + case MENU_STATE_NONE: + mSystemWindows.setShellRootAccessibilityWindow(0, SHELL_ROOT_LAYER_PIP, null); + break; + default: + mSystemWindows.setShellRootAccessibilityWindow(0, SHELL_ROOT_LAYER_PIP, + mPipMenuView); + break; + } } /** diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUIController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUIController.java index c981adee9b5c..1fc4d12def1f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUIController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUIController.java @@ -20,7 +20,6 @@ import android.annotation.Nullable; import android.content.Context; import android.content.res.Configuration; import android.hardware.display.DisplayManager; -import android.os.IBinder; import android.util.ArraySet; import android.util.Log; import android.util.SparseArray; @@ -45,6 +44,13 @@ import java.util.function.Consumer; */ public class SizeCompatUIController implements DisplayController.OnDisplaysChangedListener, DisplayImeController.ImePositionProcessor { + + /** Callback for size compat UI interaction. */ + public interface SizeCompatUICallback { + /** Called when the size compat restart button is clicked. */ + void onSizeCompatRestartButtonClicked(int taskId); + } + private static final String TAG = "SizeCompatUIController"; /** Whether the IME is shown on display id. */ @@ -61,6 +67,8 @@ public class SizeCompatUIController implements DisplayController.OnDisplaysChang private final DisplayImeController mImeController; private final SyncTransactionQueue mSyncQueue; + private SizeCompatUICallback mCallback; + /** Only show once automatically in the process life. */ private boolean mHasShownHint; @@ -76,29 +84,31 @@ public class SizeCompatUIController implements DisplayController.OnDisplaysChang mImeController.addPositionProcessor(this); } + /** Sets the callback for UI interactions. */ + public void setSizeCompatUICallback(SizeCompatUICallback callback) { + mCallback = callback; + } + /** * Called when the Task info changed. Creates and updates the size compat UI if there is an * activity in size compat, or removes the UI if there is no size compat activity. - * * @param displayId display the task and activity are in. * @param taskId task the activity is in. * @param taskConfig task config to place the size compat UI with. - * @param sizeCompatActivity the size compat activity in the task. Can be {@code null} if the - * top activity in this Task is not in size compat. * @param taskListener listener to handle the Task Surface placement. */ public void onSizeCompatInfoChanged(int displayId, int taskId, - @Nullable Configuration taskConfig, @Nullable IBinder sizeCompatActivity, + @Nullable Configuration taskConfig, @Nullable ShellTaskOrganizer.TaskListener taskListener) { - if (taskConfig == null || sizeCompatActivity == null || taskListener == null) { + if (taskConfig == null || taskListener == null) { // Null token means the current foreground activity is not in size compatibility mode. removeLayout(taskId); } else if (mActiveLayouts.contains(taskId)) { // UI already exists, update the UI layout. - updateLayout(taskId, taskConfig, sizeCompatActivity, taskListener); + updateLayout(taskId, taskConfig, taskListener); } else { // Create a new size compat UI. - createLayout(displayId, taskId, taskConfig, sizeCompatActivity, taskListener); + createLayout(displayId, taskId, taskConfig, taskListener); } } @@ -137,7 +147,7 @@ public class SizeCompatUIController implements DisplayController.OnDisplaysChang } private void createLayout(int displayId, int taskId, Configuration taskConfig, - IBinder activityToken, ShellTaskOrganizer.TaskListener taskListener) { + ShellTaskOrganizer.TaskListener taskListener) { final Context context = getOrCreateDisplayContext(displayId); if (context == null) { Log.e(TAG, "Cannot get context for display " + displayId); @@ -145,17 +155,16 @@ public class SizeCompatUIController implements DisplayController.OnDisplaysChang } final SizeCompatUILayout layout = createLayout(context, displayId, taskId, taskConfig, - activityToken, taskListener); + taskListener); mActiveLayouts.put(taskId, layout); layout.createSizeCompatButton(isImeShowingOnDisplay(displayId)); } @VisibleForTesting SizeCompatUILayout createLayout(Context context, int displayId, int taskId, - Configuration taskConfig, IBinder activityToken, - ShellTaskOrganizer.TaskListener taskListener) { - final SizeCompatUILayout layout = new SizeCompatUILayout(mSyncQueue, context, taskConfig, - taskId, activityToken, taskListener, mDisplayController.getDisplayLayout(displayId), + Configuration taskConfig, ShellTaskOrganizer.TaskListener taskListener) { + final SizeCompatUILayout layout = new SizeCompatUILayout(mSyncQueue, mCallback, context, + taskConfig, taskId, taskListener, mDisplayController.getDisplayLayout(displayId), mHasShownHint); // Only show hint for the first time. mHasShownHint = true; @@ -163,13 +172,12 @@ public class SizeCompatUIController implements DisplayController.OnDisplaysChang } private void updateLayout(int taskId, Configuration taskConfig, - IBinder sizeCompatActivity, ShellTaskOrganizer.TaskListener taskListener) { final SizeCompatUILayout layout = mActiveLayouts.get(taskId); if (layout == null) { return; } - layout.updateSizeCompatInfo(taskConfig, sizeCompatActivity, taskListener, + layout.updateSizeCompatInfo(taskConfig, taskListener, isImeShowingOnDisplay(layout.getDisplayId())); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUILayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUILayout.java index c6d994ecde8d..a5e96d14dde6 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUILayout.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUILayout.java @@ -23,13 +23,11 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERL import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; import android.annotation.Nullable; -import android.app.ActivityClient; import android.content.Context; import android.content.res.Configuration; import android.graphics.PixelFormat; import android.graphics.Rect; import android.os.Binder; -import android.os.IBinder; import android.view.SurfaceControl; import android.view.View; import android.view.WindowManager; @@ -48,11 +46,11 @@ class SizeCompatUILayout { private static final String TAG = "SizeCompatUILayout"; private final SyncTransactionQueue mSyncQueue; + private final SizeCompatUIController.SizeCompatUICallback mCallback; private Context mContext; private Configuration mTaskConfig; private final int mDisplayId; private final int mTaskId; - private IBinder mActivityToken; private ShellTaskOrganizer.TaskListener mTaskListener; private DisplayLayout mDisplayLayout; @@ -72,15 +70,16 @@ class SizeCompatUILayout { final int mPopupOffsetY; boolean mShouldShowHint; - SizeCompatUILayout(SyncTransactionQueue syncQueue, Context context, Configuration taskConfig, - int taskId, IBinder activityToken, ShellTaskOrganizer.TaskListener taskListener, + SizeCompatUILayout(SyncTransactionQueue syncQueue, + SizeCompatUIController.SizeCompatUICallback callback, Context context, + Configuration taskConfig, int taskId, ShellTaskOrganizer.TaskListener taskListener, DisplayLayout displayLayout, boolean hasShownHint) { mSyncQueue = syncQueue; + mCallback = callback; mContext = context.createConfigurationContext(taskConfig); mTaskConfig = taskConfig; mDisplayId = mContext.getDisplayId(); mTaskId = taskId; - mActivityToken = activityToken; mTaskListener = taskListener; mDisplayLayout = displayLayout; mShouldShowHint = !hasShownHint; @@ -141,12 +140,11 @@ class SizeCompatUILayout { } /** Called when size compat info changed. */ - void updateSizeCompatInfo(Configuration taskConfig, IBinder activityToken, + void updateSizeCompatInfo(Configuration taskConfig, ShellTaskOrganizer.TaskListener taskListener, boolean isImeShowing) { final Configuration prevTaskConfig = mTaskConfig; final ShellTaskOrganizer.TaskListener prevTaskListener = mTaskListener; mTaskConfig = taskConfig; - mActivityToken = activityToken; mTaskListener = taskListener; // Update configuration. @@ -253,7 +251,7 @@ class SizeCompatUILayout { /** Called when the restart button is clicked. */ void onRestartButtonClicked() { - ActivityClient.getInstance().restartActivityProcessIfVisible(mActivityToken); + mCallback.onSizeCompatRestartButtonClicked(mTaskId); } /** Called when the restart button is long clicked. */ diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl index 8f0892fdcbba..df1f5e67e4e2 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl @@ -20,6 +20,8 @@ import android.app.PendingIntent; import android.content.Intent; import android.os.Bundle; import android.os.UserHandle; +import android.view.RemoteAnimationAdapter; +import android.view.RemoteAnimationTarget; import android.window.IRemoteTransition; import com.android.wm.shell.splitscreen.ISplitScreenListener; @@ -77,9 +79,22 @@ interface ISplitScreen { int position, in Bundle options) = 9; /** - * Starts tasks simultaneously in one transition. The first task in the list will be in the - * main-stage and on the left/top. + * Starts tasks simultaneously in one transition. */ oneway void startTasks(int mainTaskId, in Bundle mainOptions, int sideTaskId, in Bundle sideOptions, int sidePosition, in IRemoteTransition remoteTransition) = 10; + + /** + * Version of startTasks using legacy transition system. + */ + oneway void startTasksWithLegacyTransition(int mainTaskId, in Bundle mainOptions, + int sideTaskId, in Bundle sideOptions, int sidePosition, + in RemoteAnimationAdapter adapter) = 11; + + /** + * Blocking call that notifies and gets additional split-screen targets when entering + * recents (for example: the dividerBar). + * @param cancel is true if leaving recents back to split (eg. the gesture was cancelled). + */ + RemoteAnimationTarget[] onGoingToRecentsLegacy(boolean cancel) = 12; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/OutlineManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/OutlineManager.java index 5d5a6e50341a..0b763f2d05f7 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/OutlineManager.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/OutlineManager.java @@ -38,8 +38,6 @@ import android.view.WindowlessWindowManager; import com.android.wm.shell.R; -import java.util.function.Supplier; - /** * Handles drawing outline of the bounds of provided root surface. The outline will be drown with * the consideration of display insets like status bar, navigation bar and display cutout. @@ -47,67 +45,71 @@ import java.util.function.Supplier; class OutlineManager extends WindowlessWindowManager { private static final String WINDOW_NAME = "SplitOutlineLayer"; private final Context mContext; - private final int mOutlineColor; private final Rect mOutlineBounds = new Rect(); private final Rect mTmpBounds = new Rect(); - private final Supplier<SurfaceControl> mOutlineSurfaceSupplier; private SurfaceControlViewHost mViewHost; + private SurfaceControl mHostLeash; + private SurfaceControl mLeash; + private int mOutlineColor; - /** - * Constructs {@link #OutlineManager} with indicated outline color for the provided root - * surface. - */ - OutlineManager(Context context, Configuration configuration, - Supplier<SurfaceControl> outlineSurfaceSupplier, int color) { + OutlineManager(Context context, Configuration configuration) { super(configuration, null /* rootSurface */, null /* hostInputToken */); - mContext = context.createDisplayContext(context.getDisplay()); - mOutlineSurfaceSupplier = outlineSurfaceSupplier; - mOutlineColor = color; + mContext = context.createWindowContext(context.getDisplay(), TYPE_APPLICATION_OVERLAY, + null /* options */); } @Override protected void attachToParentSurface(IWindow window, SurfaceControl.Builder b) { - b.setParent(mOutlineSurfaceSupplier.get()); + b.setParent(mHostLeash); } - boolean updateOutlineBounds(Rect rootBounds) { + boolean drawOutlineBounds(Rect rootBounds) { + if (mLeash == null || mViewHost == null) return false; + computeOutlineBounds(mContext, rootBounds, mTmpBounds); if (mOutlineBounds.equals(mTmpBounds)) { return false; } mOutlineBounds.set(mTmpBounds); - if (mViewHost == null) { - mViewHost = new SurfaceControlViewHost(mContext, mContext.getDisplay(), this); - } - if (mViewHost.getView() == null) { - final OutlineRoot rootView = (OutlineRoot) LayoutInflater.from(mContext) - .inflate(R.layout.split_outline, null); - rootView.updateOutlineBounds(mOutlineBounds, mOutlineColor); - - final WindowManager.LayoutParams lp = new WindowManager.LayoutParams( - rootBounds.width(), rootBounds.height(), - TYPE_APPLICATION_OVERLAY, - FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCHABLE, - PixelFormat.TRANSLUCENT); - lp.token = new Binder(); - lp.setTitle(WINDOW_NAME); - lp.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION | PRIVATE_FLAG_TRUSTED_OVERLAY; - // TODO(b/189839391): Set INPUT_FEATURE_NO_INPUT_CHANNEL after WM supports - // TRUSTED_OVERLAY for windowless window without input channel. - mViewHost.setView(rootView, lp); - } else { - ((OutlineRoot) mViewHost.getView()).updateOutlineBounds(mOutlineBounds, mOutlineColor); - final WindowManager.LayoutParams lp = - (WindowManager.LayoutParams) mViewHost.getView().getLayoutParams(); - lp.width = rootBounds.width(); - lp.height = rootBounds.height(); - mViewHost.relayout(lp); - } + ((OutlineRoot) mViewHost.getView()).updateOutlineBounds(mOutlineBounds, mOutlineColor); + final WindowManager.LayoutParams lp = + (WindowManager.LayoutParams) mViewHost.getView().getLayoutParams(); + lp.width = rootBounds.width(); + lp.height = rootBounds.height(); + mViewHost.relayout(lp); return true; } + void inflate(SurfaceControl.Transaction t, SurfaceControl hostLeash, int color) { + if (mLeash != null || mViewHost != null) return; + + mHostLeash = hostLeash; + mOutlineColor = color; + mViewHost = new SurfaceControlViewHost(mContext, mContext.getDisplay(), this); + final OutlineRoot rootView = (OutlineRoot) LayoutInflater.from(mContext) + .inflate(R.layout.split_outline, null); + + final WindowManager.LayoutParams lp = new WindowManager.LayoutParams( + 0 /* width */, 0 /* height */, TYPE_APPLICATION_OVERLAY, + FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCHABLE, PixelFormat.TRANSLUCENT); + lp.token = new Binder(); + lp.setTitle(WINDOW_NAME); + lp.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION | PRIVATE_FLAG_TRUSTED_OVERLAY; + // TODO(b/189839391): Set INPUT_FEATURE_NO_INPUT_CHANNEL after WM supports + // TRUSTED_OVERLAY for windowless window without input channel. + mViewHost.setView(rootView, lp); + mLeash = getSurfaceControl(mViewHost.getWindowToken()); + t.setLayer(mLeash, Integer.MAX_VALUE); + } + + void release() { + if (mViewHost != null) { + mViewHost.release(); + } + } + private static void computeOutlineBounds(Context context, Rect rootBounds, Rect outBounds) { computeDisplayStableBounds(context, outBounds); outBounds.intersect(rootBounds); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java index a0bdcc3edd5f..2b19bb965fed 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java @@ -21,7 +21,6 @@ import android.app.ActivityManager; import android.content.Context; import android.graphics.Color; import android.graphics.Rect; -import android.view.SurfaceControl; import android.view.SurfaceSession; import android.window.WindowContainerToken; import android.window.WindowContainerTransaction; @@ -52,7 +51,7 @@ class SideStage extends StageTaskListener { final WindowContainerToken rootToken = mRootTaskInfo.token; wct.setBounds(rootToken, rootBounds) .reparent(task.token, rootToken, true /* onTop*/) - // Moving the root task to top after the child tasks were repareted , or the root + // Moving the root task to top after the child tasks were reparented , or the root // task cannot be visible and focused. .reorder(rootToken, true /* onTop */); } @@ -78,25 +77,33 @@ class SideStage extends StageTaskListener { return true; } - @Override - @CallSuper - public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) { - super.onTaskAppeared(taskInfo, leash); - if (mRootTaskInfo != null && mRootTaskInfo.taskId == taskInfo.taskId) { - mOutlineManager = new OutlineManager(mContext, mRootTaskInfo.configuration, - () -> mRootLeash, - Color.YELLOW); + void enableOutline(boolean enable) { + if (enable) { + if (mOutlineManager == null && mRootTaskInfo != null) { + mOutlineManager = new OutlineManager(mContext, mRootTaskInfo.configuration); + mSyncQueue.runInSync(t -> mOutlineManager.inflate(t, mRootLeash, Color.YELLOW)); + updateOutlineBounds(); + } + } else { + if (mOutlineManager != null) { + mOutlineManager.release(); + mOutlineManager = null; + } } } + private void updateOutlineBounds() { + if (mOutlineManager == null || mRootTaskInfo == null || !mRootTaskInfo.isVisible) return; + mOutlineManager.drawOutlineBounds( + mRootTaskInfo.configuration.windowConfiguration.getBounds()); + } + @Override @CallSuper public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) { super.onTaskInfoChanged(taskInfo); - if (mRootTaskInfo != null && mRootTaskInfo.taskId == taskInfo.taskId - && mRootTaskInfo.isRunning) { - mOutlineManager.updateOutlineBounds( - mRootTaskInfo.configuration.windowConfiguration.getBounds()); + if (mRootTaskInfo != null && mRootTaskInfo.taskId == taskInfo.taskId) { + updateOutlineBounds(); } } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java index 89e6ca86487f..d60fa29d8f77 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java @@ -39,6 +39,8 @@ import android.os.IBinder; import android.os.RemoteException; import android.os.UserHandle; import android.util.Slog; +import android.view.RemoteAnimationAdapter; +import android.view.RemoteAnimationTarget; import android.window.IRemoteTransition; import androidx.annotation.BinderThread; @@ -140,6 +142,10 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, return mStageCoordinator.removeFromSideStage(taskId); } + public void setSideStageOutline(boolean enable) { + mStageCoordinator.setSideStageOutline(enable); + } + public void setSideStagePosition(@SplitPosition int sideStagePosition) { mStageCoordinator.setSideStagePosition(sideStagePosition); } @@ -266,6 +272,11 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, return options; } + RemoteAnimationTarget[] onGoingToRecentsLegacy(boolean cancel) { + if (!isSplitScreenVisible()) return null; + return new RemoteAnimationTarget[]{mStageCoordinator.getDividerBarLegacyTarget()}; + } + public void dump(@NonNull PrintWriter pw, String prefix) { pw.println(prefix + TAG); if (mStageCoordinator != null) { @@ -428,6 +439,16 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, } @Override + public void startTasksWithLegacyTransition(int mainTaskId, @Nullable Bundle mainOptions, + int sideTaskId, @Nullable Bundle sideOptions, @SplitPosition int sidePosition, + RemoteAnimationAdapter adapter) { + executeRemoteCallWithTaskPermission(mController, "startTasks", + (controller) -> controller.mStageCoordinator.startTasksWithLegacyTransition( + mainTaskId, mainOptions, sideTaskId, sideOptions, sidePosition, + adapter)); + } + + @Override public void startTasks(int mainTaskId, @Nullable Bundle mainOptions, int sideTaskId, @Nullable Bundle sideOptions, @SplitPosition int sidePosition, @@ -455,5 +476,14 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, controller.startIntent(intent, fillInIntent, stage, position, options); }); } + + @Override + public RemoteAnimationTarget[] onGoingToRecentsLegacy(boolean cancel) { + final RemoteAnimationTarget[][] out = new RemoteAnimationTarget[][]{null}; + executeRemoteCallWithTaskPermission(mController, "onGoingToRecentsLegacy", + (controller) -> out[0] = controller.onGoingToRecentsLegacy(cancel), + true /* blocking */); + return out[0]; + } } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java index c6aacb1ab501..67b5ab390042 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java @@ -20,6 +20,7 @@ import static android.app.ActivityOptions.KEY_LAUNCH_ROOT_TASK_TOKEN; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; +import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; import static android.view.WindowManager.TRANSIT_OPEN; import static android.view.WindowManager.TRANSIT_TO_BACK; import static android.view.WindowManager.TRANSIT_TO_FRONT; @@ -42,12 +43,21 @@ import static com.android.wm.shell.transition.Transitions.isOpeningType; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; +import android.app.ActivityOptions; +import android.app.ActivityTaskManager; +import android.app.WindowConfiguration; import android.content.Context; import android.graphics.Rect; import android.hardware.devicestate.DeviceStateManager; import android.os.Bundle; import android.os.IBinder; +import android.os.RemoteException; import android.util.Log; +import android.util.Slog; +import android.view.IRemoteAnimationFinishedCallback; +import android.view.IRemoteAnimationRunner; +import android.view.RemoteAnimationAdapter; +import android.view.RemoteAnimationTarget; import android.view.SurfaceControl; import android.view.SurfaceSession; import android.view.WindowManager; @@ -222,6 +232,10 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, return result; } + void setSideStageOutline(boolean enable) { + mSideStage.enableOutline(enable); + } + /** Starts 2 tasks in one transition. */ void startTasks(int mainTaskId, @Nullable Bundle mainOptions, int sideTaskId, @Nullable Bundle sideOptions, @SplitPosition int sidePosition, @@ -248,6 +262,75 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, TRANSIT_SPLIT_SCREEN_PAIR_OPEN, wct, remoteTransition, this); } + /** Starts 2 tasks in one legacy transition. */ + void startTasksWithLegacyTransition(int mainTaskId, @Nullable Bundle mainOptions, + int sideTaskId, @Nullable Bundle sideOptions, @SplitPosition int sidePosition, + RemoteAnimationAdapter adapter) { + final WindowContainerTransaction wct = new WindowContainerTransaction(); + // Need to add another wrapper here in shell so that we can inject the divider bar + // and also manage the process elevation via setRunningRemote + IRemoteAnimationRunner wrapper = new IRemoteAnimationRunner.Stub() { + @Override + public void onAnimationStart(@WindowManager.TransitionOldType int transit, + RemoteAnimationTarget[] apps, + RemoteAnimationTarget[] wallpapers, + RemoteAnimationTarget[] nonApps, + final IRemoteAnimationFinishedCallback finishedCallback) { + RemoteAnimationTarget[] augmentedNonApps = + new RemoteAnimationTarget[nonApps.length + 1]; + for (int i = 0; i < nonApps.length; ++i) { + augmentedNonApps[i] = nonApps[i]; + } + augmentedNonApps[augmentedNonApps.length - 1] = getDividerBarLegacyTarget(); + try { + ActivityTaskManager.getService().setRunningRemoteTransitionDelegate( + adapter.getCallingApplication()); + adapter.getRunner().onAnimationStart(transit, apps, wallpapers, nonApps, + finishedCallback); + } catch (RemoteException e) { + Slog.e(TAG, "Error starting remote animation", e); + } + } + + @Override + public void onAnimationCancelled() { + try { + adapter.getRunner().onAnimationCancelled(); + } catch (RemoteException e) { + Slog.e(TAG, "Error starting remote animation", e); + } + } + }; + RemoteAnimationAdapter wrappedAdapter = new RemoteAnimationAdapter( + wrapper, adapter.getDuration(), adapter.getStatusBarTransitionDelay()); + + if (mainOptions == null) { + mainOptions = ActivityOptions.makeRemoteAnimation(wrappedAdapter).toBundle(); + } else { + ActivityOptions mainActivityOptions = ActivityOptions.fromBundle(mainOptions); + mainActivityOptions.update(ActivityOptions.makeRemoteAnimation(wrappedAdapter)); + } + + sideOptions = sideOptions != null ? sideOptions : new Bundle(); + setSideStagePosition(sidePosition); + + // Build a request WCT that will launch both apps such that task 0 is on the main stage + // while task 1 is on the side stage. + mMainStage.activate(getMainStageBounds(), wct); + mSideStage.setBounds(getSideStageBounds(), wct); + + // Make sure the launch options will put tasks in the corresponding split roots + addActivityOptions(mainOptions, mMainStage); + addActivityOptions(sideOptions, mSideStage); + + // Add task launch requests + wct.startTask(mainTaskId, mainOptions); + wct.startTask(sideTaskId, sideOptions); + + // Using legacy transitions, so we can't use blast sync since it conflicts. + mTaskOrganizer.applyTransaction(wct); + } + @SplitLayout.SplitPosition int getSideStagePosition() { return mSideStagePosition; @@ -432,7 +515,11 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, exitSplitScreen(toTop); } - if (mainStageVisible) { + // When both stage's visibility changed to visible, main stage might receives visibility + // changed before side stage if it has higher z-order than side stage. Make sure we only + // update main stage's windowing mode with the visibility changed of side stage to prevent + // stacking multiple windowing mode transactions which result to flicker issue. + if (mainStageVisible && stageListener == mSideStageListener) { final WindowContainerTransaction wct = new WindowContainerTransaction(); if (sideStageVisible) { // The main stage configuration should to follow split layout when side stage is @@ -510,10 +597,6 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, // Make sure the main stage is active. mMainStage.activate(getMainStageBounds(), wct); mSideStage.setBounds(getSideStageBounds(), wct); - // Reorder side stage to the top whenever there's a new child task appeared in side - // stage. This is needed to prevent main stage occludes side stage and makes main stage - // flipping between fullscreen and multi-window windowing mode. - wct.reorder(mSideStage.mRootTaskInfo.token, true); mTaskOrganizer.applyTransaction(wct); } } @@ -891,6 +974,16 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, } } + RemoteAnimationTarget getDividerBarLegacyTarget() { + final Rect bounds = mSplitLayout.getDividerBounds(); + return new RemoteAnimationTarget(-1 /* taskId */, -1 /* mode */, + mSplitLayout.getDividerLeash(), false /* isTranslucent */, null /* clipRect */, + null /* contentInsets */, Integer.MAX_VALUE /* prefixOrderIndex */, + new android.graphics.Point(0, 0) /* position */, bounds, bounds, + new WindowConfiguration(), true, null /* startLeash */, null /* startBounds */, + null /* taskInfo */, TYPE_DOCK_DIVIDER); + } + @Override public void dump(@NonNull PrintWriter pw, String prefix) { final String innerPrefix = prefix + " "; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java index 0fd8eca6290e..4f73feec750d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java @@ -71,8 +71,8 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener { } private final StageListenerCallbacks mCallbacks; - private final SyncTransactionQueue mSyncQueue; private final SurfaceSession mSurfaceSession; + protected final SyncTransactionQueue mSyncQueue; protected ActivityManager.RunningTaskInfo mRootTaskInfo; protected SurfaceControl mRootLeash; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java index 75dd561ffc61..107a3f880354 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java @@ -127,11 +127,13 @@ public class SplashscreenContentDrawer { * parallel. * * @param suggestType Suggest type to create the splash screen view. - * @param consumer Receiving the SplashScreenView object, which will also be executed - * on splash screen thread. Note that the view can be null if failed. + * @param splashScreenViewConsumer Receiving the SplashScreenView object, which will also be + * executed on splash screen thread. Note that the view can be + * null if failed. + * @param bgColorConsumer Receiving the background color once it's estimated complete. */ void createContentView(Context context, @StartingWindowType int suggestType, ActivityInfo info, - int taskId, Consumer<SplashScreenView> consumer) { + int taskId, Consumer<SplashScreenView> splashScreenViewConsumer) { mSplashscreenWorkerHandler.post(() -> { SplashScreenView contentView; try { @@ -143,7 +145,7 @@ public class SplashscreenContentDrawer { + taskId, e); contentView = null; } - consumer.accept(contentView); + splashScreenViewConsumer.accept(contentView); }); } @@ -160,7 +162,10 @@ public class SplashscreenContentDrawer { com.android.wm.shell.R.dimen.starting_surface_exit_animation_window_shift_length); } - private static int getSystemBGColor() { + /** + * @return Current system background color. + */ + public static int getSystemBGColor() { final Context systemContext = ActivityThread.currentApplication(); if (systemContext == null) { Slog.e(TAG, "System context does not exist!"); @@ -170,12 +175,22 @@ public class SplashscreenContentDrawer { return res.getColor(com.android.wm.shell.R.color.splash_window_background_default); } + /** + * Estimate the background color of the app splash screen, this may take a while so use it only + * if there is no starting window exists for that context. + **/ + int estimateTaskBackgroundColor(Context context) { + final SplashScreenWindowAttrs windowAttrs = new SplashScreenWindowAttrs(); + getWindowAttrs(context, windowAttrs); + return peekWindowBGColor(context, windowAttrs); + } + private static Drawable createDefaultBackgroundDrawable() { return new ColorDrawable(getSystemBGColor()); } /** Extract the window background color from {@code attrs}. */ - public static int peekWindowBGColor(Context context, SplashScreenWindowAttrs attrs) { + private static int peekWindowBGColor(Context context, SplashScreenWindowAttrs attrs) { Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "peekWindowBGColor"); final Drawable themeBGDrawable; if (attrs.mWindowBgColor != 0) { @@ -255,7 +270,7 @@ public class SplashscreenContentDrawer { * Get the {@link SplashScreenWindowAttrs} from {@code context} and fill them into * {@code attrs}. */ - public static void getWindowAttrs(Context context, SplashScreenWindowAttrs attrs) { + private static void getWindowAttrs(Context context, SplashScreenWindowAttrs attrs) { final TypedArray typedArray = context.obtainStyledAttributes( com.android.internal.R.styleable.Window); attrs.mWindowBgResId = typedArray.getResourceId(R.styleable.Window_windowBackground, 0); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java index 079d68973852..01c9b6630fa6 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java @@ -16,6 +16,8 @@ package com.android.wm.shell.startingsurface; +import android.app.TaskInfo; +import android.graphics.Color; /** * Interface to engage starting window feature. */ @@ -27,4 +29,11 @@ public interface StartingSurface { default IStartingWindow createExternalInterface() { return null; } + + /** + * Returns the background color for a starting window if existing. + */ + default int getBackgroundColor(TaskInfo taskInfo) { + return Color.BLACK; + } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java index 3cbce9c38f12..243751fe13e8 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java @@ -26,17 +26,22 @@ import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SNAPSHOT; import android.annotation.Nullable; import android.app.ActivityManager.RunningTaskInfo; import android.app.ActivityTaskManager; +import android.app.ActivityThread; +import android.app.TaskInfo; import android.content.Context; import android.content.pm.ActivityInfo; +import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.TypedArray; +import android.graphics.Color; import android.graphics.PixelFormat; import android.graphics.Rect; import android.hardware.display.DisplayManager; import android.os.IBinder; import android.os.RemoteCallback; +import android.os.RemoteException; import android.os.Trace; import android.os.UserHandle; import android.util.Slog; @@ -149,6 +154,12 @@ public class StartingSurfaceDrawer { return context.createDisplayContext(targetDisplay); } + private int getSplashScreenTheme(int splashScreenThemeResId, ActivityInfo activityInfo) { + return splashScreenThemeResId != 0 + ? splashScreenThemeResId + : activityInfo.getThemeResource() != 0 ? activityInfo.getThemeResource() + : com.android.internal.R.style.Theme_DeviceDefault_DayNight; + } /** * Called when a task need a splash screen starting window. * @@ -170,10 +181,7 @@ public class StartingSurfaceDrawer { final int taskId = taskInfo.taskId; Context context = mContext; // replace with the default theme if the application didn't set - final int theme = windowInfo.splashScreenThemeResId != 0 - ? windowInfo.splashScreenThemeResId - : activityInfo.getThemeResource() != 0 ? activityInfo.getThemeResource() - : com.android.internal.R.style.Theme_DeviceDefault_DayNight; + final int theme = getSplashScreenTheme(windowInfo.splashScreenThemeResId, activityInfo); if (DEBUG_SPLASH_SCREEN) { Slog.d(TAG, "addSplashScreen " + activityInfo.packageName + " theme=" + Integer.toHexString(theme) + " task=" + taskInfo.taskId @@ -299,6 +307,7 @@ public class StartingSurfaceDrawer { final SplashScreenViewSupplier viewSupplier = new SplashScreenViewSupplier(); final FrameLayout rootLayout = new FrameLayout(context); rootLayout.setPadding(0, 0, 0, 0); + rootLayout.setFitsSystemWindows(false); final Runnable setViewSynchronized = () -> { Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "addSplashScreenView"); // waiting for setContentView before relayoutWindow @@ -335,6 +344,10 @@ public class StartingSurfaceDrawer { // the window before first round relayoutWindow, which will happen after insets // animation. mChoreographer.postCallback(CALLBACK_INSETS_ANIMATION, setViewSynchronized, null); + // Block until we get the background color. + final StartingWindowRecord record = mStartingWindowRecords.get(taskId); + final SplashScreenView contentView = viewSupplier.get(); + record.mBGColor = contentView.getInitBackgroundColor(); } } catch (RuntimeException e) { // don't crash if something else bad happens, for example a @@ -345,11 +358,11 @@ public class StartingSurfaceDrawer { } int getStartingWindowBackgroundColorForTask(int taskId) { - StartingWindowRecord startingWindowRecord = mStartingWindowRecords.get(taskId); - if (startingWindowRecord == null || startingWindowRecord.mContentView == null) { - return 0; + final StartingWindowRecord startingWindowRecord = mStartingWindowRecords.get(taskId); + if (startingWindowRecord == null) { + return Color.TRANSPARENT; } - return startingWindowRecord.mContentView.getInitBackgroundColor(); + return startingWindowRecord.mBGColor; } private static class SplashScreenViewSupplier implements Supplier<SplashScreenView> { @@ -377,6 +390,43 @@ public class StartingSurfaceDrawer { } } + int estimateTaskBackgroundColor(TaskInfo taskInfo) { + if (taskInfo.topActivityInfo == null) { + return Color.TRANSPARENT; + } + final ActivityInfo activityInfo = taskInfo.topActivityInfo; + final String packageName = activityInfo.packageName; + final int userId = taskInfo.userId; + final Context windowContext; + try { + windowContext = mContext.createPackageContextAsUser( + packageName, Context.CONTEXT_RESTRICTED, UserHandle.of(userId)); + } catch (PackageManager.NameNotFoundException e) { + Slog.w(TAG, "Failed creating package context with package name " + + packageName + " for user " + taskInfo.userId, e); + return Color.TRANSPARENT; + } + try { + final IPackageManager packageManager = ActivityThread.getPackageManager(); + final String splashScreenThemeName = packageManager.getSplashScreenTheme(packageName, + userId); + final int splashScreenThemeId = splashScreenThemeName != null + ? windowContext.getResources().getIdentifier(splashScreenThemeName, null, null) + : 0; + + final int theme = getSplashScreenTheme(splashScreenThemeId, activityInfo); + + if (theme != windowContext.getThemeResId()) { + windowContext.setTheme(theme); + } + return mSplashscreenContentDrawer.estimateTaskBackgroundColor(windowContext); + } catch (RuntimeException | RemoteException e) { + Slog.w(TAG, "failed get starting window background color at taskId: " + + taskInfo.taskId, e); + } + return Color.TRANSPARENT; + } + /** * Called when a task need a snapshot starting window. */ @@ -555,19 +605,16 @@ public class StartingSurfaceDrawer { private SplashScreenView mContentView; private boolean mSetSplashScreen; private @StartingWindowType int mSuggestType; - - StartingWindowRecord(IBinder appToken, View decorView, - TaskSnapshotWindow taskSnapshotWindow) { - mAppToken = appToken; - mDecorView = decorView; - mTaskSnapshotWindow = taskSnapshotWindow; - } + private int mBGColor; StartingWindowRecord(IBinder appToken, View decorView, TaskSnapshotWindow taskSnapshotWindow, @StartingWindowType int suggestType) { mAppToken = appToken; mDecorView = decorView; mTaskSnapshotWindow = taskSnapshotWindow; + if (mTaskSnapshotWindow != null) { + mBGColor = mTaskSnapshotWindow.getBackgroundColor(); + } mSuggestType = suggestType; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java index eaa89d8e3ab5..e84d498a9258 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java @@ -18,18 +18,23 @@ package com.android.wm.shell.startingsurface; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN; import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN; +import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_NONE; import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SNAPSHOT; import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SPLASH_SCREEN; import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission; import android.app.ActivityManager.RunningTaskInfo; +import android.app.TaskInfo; import android.content.Context; +import android.graphics.Color; import android.graphics.Rect; +import android.os.Build; import android.os.IBinder; import android.os.RemoteException; import android.os.Trace; import android.util.Slog; +import android.util.SparseIntArray; import android.view.SurfaceControl; import android.window.StartingWindowInfo; import android.window.StartingWindowInfo.StartingWindowType; @@ -38,6 +43,7 @@ import android.window.TaskSnapshot; import androidx.annotation.BinderThread; +import com.android.internal.annotations.GuardedBy; import com.android.internal.util.function.TriConsumer; import com.android.wm.shell.common.RemoteCallable; import com.android.wm.shell.common.ShellExecutor; @@ -62,10 +68,11 @@ import com.android.wm.shell.common.TransactionPool; public class StartingWindowController implements RemoteCallable<StartingWindowController> { private static final String TAG = StartingWindowController.class.getSimpleName(); - // TODO b/183150443 Keep this flag open for a while, several things might need to adjust. - public static final boolean DEBUG_SPLASH_SCREEN = true; + public static final boolean DEBUG_SPLASH_SCREEN = Build.isDebuggable(); public static final boolean DEBUG_TASK_SNAPSHOT = false; + private static final long TASK_BG_COLOR_RETAIN_TIME_MS = 5000; + private final StartingSurfaceDrawer mStartingSurfaceDrawer; private final StartingWindowTypeAlgorithm mStartingWindowTypeAlgorithm; @@ -73,6 +80,11 @@ public class StartingWindowController implements RemoteCallable<StartingWindowCo private final StartingSurfaceImpl mImpl = new StartingSurfaceImpl(); private final Context mContext; private final ShellExecutor mSplashScreenExecutor; + /** + * Need guarded because it has exposed to StartingSurface + */ + @GuardedBy("mTaskBackgroundColors") + private final SparseIntArray mTaskBackgroundColors = new SparseIntArray(); public StartingWindowController(Context context, ShellExecutor splashScreenExecutor, StartingWindowTypeAlgorithm startingWindowTypeAlgorithm, TransactionPool pool) { @@ -125,13 +137,19 @@ public class StartingWindowController implements RemoteCallable<StartingWindowCo final TaskSnapshot snapshot = windowInfo.mTaskSnapshot; mStartingSurfaceDrawer.makeTaskSnapshotWindow(windowInfo, appToken, snapshot); - } else /* suggestionType == STARTING_WINDOW_TYPE_NONE */ { - // Don't add a staring window. } - if (mTaskLaunchingCallback != null && isSplashScreenType(suggestionType)) { + if (suggestionType != STARTING_WINDOW_TYPE_NONE) { int taskId = runningTaskInfo.taskId; - int color = mStartingSurfaceDrawer.getStartingWindowBackgroundColorForTask(taskId); - mTaskLaunchingCallback.accept(taskId, suggestionType, color); + int color = mStartingSurfaceDrawer + .getStartingWindowBackgroundColorForTask(taskId); + if (color != Color.TRANSPARENT) { + synchronized (mTaskBackgroundColors) { + mTaskBackgroundColors.append(taskId, color); + } + } + if (mTaskLaunchingCallback != null && isSplashScreenType(suggestionType)) { + mTaskLaunchingCallback.accept(taskId, suggestionType, color); + } } Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); @@ -163,9 +181,13 @@ public class StartingWindowController implements RemoteCallable<StartingWindowCo */ public void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame, boolean playRevealAnimation) { - mSplashScreenExecutor.execute(() -> { - mStartingSurfaceDrawer.removeStartingWindow(taskId, leash, frame, playRevealAnimation); - }); + mSplashScreenExecutor.execute(() -> mStartingSurfaceDrawer.removeStartingWindow( + taskId, leash, frame, playRevealAnimation)); + mSplashScreenExecutor.executeDelayed(() -> { + synchronized (mTaskBackgroundColors) { + mTaskBackgroundColors.delete(taskId); + } + }, TASK_BG_COLOR_RETAIN_TIME_MS); } /** @@ -182,6 +204,19 @@ public class StartingWindowController implements RemoteCallable<StartingWindowCo mIStartingWindow = new IStartingWindowImpl(StartingWindowController.this); return mIStartingWindow; } + + @Override + public int getBackgroundColor(TaskInfo taskInfo) { + synchronized (mTaskBackgroundColors) { + final int index = mTaskBackgroundColors.indexOfKey(taskInfo.taskId); + if (index >= 0) { + return mTaskBackgroundColors.valueAt(index); + } + } + final int color = mStartingSurfaceDrawer.estimateTaskBackgroundColor(taskInfo); + return color != Color.TRANSPARENT + ? color : SplashscreenContentDrawer.getSystemBGColor(); + } } /** diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java index 382d5806e3c2..6052d3dee891 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java @@ -283,6 +283,10 @@ public class TaskSnapshotWindow { mClearWindowHandler = clearWindowHandler; } + int getBackgroundColor() { + return mBackgroundPaint.getColor(); + } + /** * Ask system bar background painter to draw status bar background. * @hide diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsTransition.kt index 512fd9a58ea8..277aca8fc01d 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsTransition.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsTransition.kt @@ -22,7 +22,10 @@ import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.setRotation import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen +import com.android.wm.shell.flicker.helpers.BaseAppHelper.Companion.isShellTransitionsEnabled import com.android.wm.shell.flicker.helpers.SplitScreenHelper +import org.junit.Assume.assumeFalse +import org.junit.Before import org.junit.Test abstract class RotateTwoLaunchedAppsTransition( @@ -52,6 +55,13 @@ abstract class RotateTwoLaunchedAppsTransition( } } + @Before + override fun setup() { + // AppPairs hasn't been updated to Shell Transition. There will be conflict on rotation. + assumeFalse(isShellTransitionsEnabled()) + super.setup() + } + @FlakyTest @Test override fun navBarLayerIsAlwaysVisible() { diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt index 4fe69ad7fabe..f15044ef37af 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt @@ -20,6 +20,7 @@ import android.app.Instrumentation import android.content.ComponentName import android.content.pm.PackageManager.FEATURE_LEANBACK import android.content.pm.PackageManager.FEATURE_LEANBACK_ONLY +import android.os.SystemProperties import android.support.test.launcherhelper.LauncherStrategyFactory import android.util.Log import androidx.test.uiautomator.By @@ -60,6 +61,9 @@ abstract class BaseAppHelper( companion object { private const val APP_CLOSE_WAIT_TIME_MS = 3_000L + fun isShellTransitionsEnabled() = + SystemProperties.getBoolean("persist.debug.shell_transit", false) + fun executeShellCommand(instrumentation: Instrumentation, cmd: String) { try { SystemUtil.runShellCommand(instrumentation, cmd) diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenTransition.kt index e8d4d1e9ada2..16dfd853209f 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenTransition.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenTransition.kt @@ -32,10 +32,12 @@ import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen import com.android.server.wm.flicker.repetitions import com.android.server.wm.flicker.startRotation import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper +import com.android.wm.shell.flicker.helpers.BaseAppHelper.Companion.isShellTransitionsEnabled import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.getDevEnableNonResizableMultiWindow import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.setDevEnableNonResizableMultiWindow import com.android.wm.shell.flicker.helpers.SplitScreenHelper import org.junit.After +import org.junit.Assume.assumeFalse import org.junit.Before import org.junit.Test @@ -52,6 +54,8 @@ abstract class LegacySplitScreenTransition(protected val testSpec: FlickerTestPa @Before open fun setup() { + // Legacy split is having some issue with Shell transition, and will be deprecated soon. + assumeFalse(isShellTransitionsEnabled()) prevDevEnableNonResizableMultiWindow = getDevEnableNonResizableMultiWindow(context) if (prevDevEnableNonResizableMultiWindow != 0) { // Turn off the development option diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java index df0a856db73c..6b74b620dad7 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java @@ -48,6 +48,7 @@ import android.view.SurfaceControl; import android.window.ITaskOrganizer; import android.window.ITaskOrganizerController; import android.window.TaskAppearedInfo; +import android.window.WindowContainerToken; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; @@ -289,7 +290,6 @@ public class ShellTaskOrganizerTests { public void testOnSizeCompatActivityChanged() { final RunningTaskInfo taskInfo1 = createTaskInfo(12, WINDOWING_MODE_FULLSCREEN); taskInfo1.displayId = DEFAULT_DISPLAY; - taskInfo1.topActivityToken = mock(IBinder.class); taskInfo1.topActivityInSizeCompat = false; final TrackingTaskListener taskListener = new TrackingTaskListener(); mOrganizer.addListenerForType(taskListener, TASK_LISTENER_TYPE_FULLSCREEN); @@ -297,23 +297,34 @@ public class ShellTaskOrganizerTests { // sizeCompatActivity is null if top activity is not in size compat. verify(mSizeCompatUI).onSizeCompatInfoChanged(taskInfo1.displayId, taskInfo1.taskId, - null /* taskConfig */, null /* sizeCompatActivity*/, null /* taskListener */); + null /* taskConfig */, null /* taskListener */); // sizeCompatActivity is non-null if top activity is in size compat. clearInvocations(mSizeCompatUI); final RunningTaskInfo taskInfo2 = createTaskInfo(taskInfo1.taskId, taskInfo1.getWindowingMode()); taskInfo2.displayId = taskInfo1.displayId; - taskInfo2.topActivityToken = taskInfo1.topActivityToken; taskInfo2.topActivityInSizeCompat = true; + taskInfo2.isVisible = true; mOrganizer.onTaskInfoChanged(taskInfo2); verify(mSizeCompatUI).onSizeCompatInfoChanged(taskInfo1.displayId, taskInfo1.taskId, - taskInfo1.configuration, taskInfo1.topActivityToken, taskListener); + taskInfo1.configuration, taskListener); + + // Not show size compat UI if task is not visible. + clearInvocations(mSizeCompatUI); + final RunningTaskInfo taskInfo3 = + createTaskInfo(taskInfo1.taskId, taskInfo1.getWindowingMode()); + taskInfo3.displayId = taskInfo1.displayId; + taskInfo3.topActivityInSizeCompat = true; + taskInfo3.isVisible = false; + mOrganizer.onTaskInfoChanged(taskInfo3); + verify(mSizeCompatUI).onSizeCompatInfoChanged(taskInfo1.displayId, taskInfo1.taskId, + null /* taskConfig */, null /* taskListener */); clearInvocations(mSizeCompatUI); mOrganizer.onTaskVanished(taskInfo1); verify(mSizeCompatUI).onSizeCompatInfoChanged(taskInfo1.displayId, taskInfo1.taskId, - null /* taskConfig */, null /* sizeCompatActivity*/, null /* taskListener */); + null /* taskConfig */, null /* taskListener */); } @Test @@ -433,6 +444,18 @@ public class ShellTaskOrganizerTests { assertEquals(listener.invisibleLocusTasks.size(), 0); } + @Test + public void testOnSizeCompatRestartButtonClicked() throws RemoteException { + RunningTaskInfo task1 = createTaskInfo(1, WINDOWING_MODE_MULTI_WINDOW); + task1.token = mock(WindowContainerToken.class); + + mOrganizer.onTaskAppeared(task1, null); + + mOrganizer.onSizeCompatRestartButtonClicked(task1.taskId); + + verify(mTaskOrganizerController).restartTaskTopActivityProcessIfVisible(task1.token); + } + private static RunningTaskInfo createTaskInfo(int taskId, int windowingMode) { RunningTaskInfo taskInfo = new RunningTaskInfo(); taskInfo.taskId = taskId; diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java index be786fb55b30..b224ae6a19b5 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java @@ -26,6 +26,7 @@ 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.anyInt; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; @@ -237,13 +238,6 @@ public class OneHandedControllerTest extends OneHandedTestCase { } @Test - public void testSettingsObserverUpdateTimeout() { - mSpiedOneHandedController.onTimeoutSettingChanged(); - - verify(mSpiedTimeoutHandler, atLeastOnce()).setTimeout(anyInt()); - } - - @Test public void testSettingsObserverUpdateSwipeToNotification() { mSpiedOneHandedController.onSwipeToNotificationEnabledChanged(); @@ -406,7 +400,7 @@ public class OneHandedControllerTest extends OneHandedTestCase { false); mSpiedOneHandedController.onActivatedActionChanged(); - verify(mSpiedOneHandedController).notifyUserConfigChanged(anyBoolean()); + verify(mMockSettingsUitl).setOneHandedModeEnabled(any(), eq(1), anyInt()); } @Test @@ -441,7 +435,7 @@ public class OneHandedControllerTest extends OneHandedTestCase { mSpiedOneHandedController.registerEventCallback(mMockEventCallback); mSpiedOneHandedController.setOneHandedEnabled(true); - verify(mSpiedOneHandedController).notifyShortcutState(anyInt()); + verify(mSpiedOneHandedController).notifyShortcutStateChanged(anyInt()); } @Test @@ -468,7 +462,7 @@ public class OneHandedControllerTest extends OneHandedTestCase { false /* To avoid test runner create Toast */); mSpiedOneHandedController.onActivatedActionChanged(); - verify(mSpiedOneHandedController).notifyUserConfigChanged(anyBoolean()); + verify(mMockSettingsUitl).setOneHandedModeEnabled(any(), eq(1), anyInt()); } @Test @@ -481,6 +475,5 @@ public class OneHandedControllerTest extends OneHandedTestCase { mSpiedOneHandedController.onActivatedActionChanged(); verify(mMockSettingsUitl, never()).setOneHandedModeEnabled(any(), anyInt(), anyInt()); - verify(mSpiedOneHandedController, never()).notifyUserConfigChanged(anyBoolean()); } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java index 1bc2a0823ff7..25bdb8ef9263 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java @@ -19,8 +19,6 @@ package com.android.wm.shell.onehanded; import static com.android.wm.shell.onehanded.OneHandedState.STATE_ENTERING; import static com.android.wm.shell.onehanded.OneHandedState.STATE_NONE; -import static com.google.common.truth.Truth.assertThat; - import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.never; @@ -68,25 +66,18 @@ public class OneHandedTutorialHandlerTest extends OneHandedTestCase { mDisplayLayout = new DisplayLayout(mContext, mDisplay); mSpiedTransitionState = spy(new OneHandedState()); mSpiedTutorialHandler = spy( - new OneHandedTutorialHandler(mContext, mDisplayLayout, mMockWindowManager, - mMockSettingsUtil, mMockShellMainExecutor)); + new OneHandedTutorialHandler(mContext, mMockWindowManager)); mTimeoutHandler = new OneHandedTimeoutHandler(mMockShellMainExecutor); } @Test - public void testDefaultZeroShownCounts_canShowTutorial() { - assertThat(mSpiedTutorialHandler.canShowTutorial()).isTrue(); - verify(mMockShellMainExecutor, never()).execute(any()); - } - - @Test public void testDefaultZeroShownCounts_doNotAttachWindow() { verify(mMockShellMainExecutor, never()).execute(any()); } @Test public void testOnStateChangedEntering_createViewAndAttachToWindow() { - when(mSpiedTutorialHandler.canShowTutorial()).thenReturn(true); + when(mSpiedTutorialHandler.isShowing()).thenReturn(true); try { mSpiedTutorialHandler.onStateChanged(STATE_ENTERING); } catch (ClassCastException e) { @@ -98,7 +89,7 @@ public class OneHandedTutorialHandlerTest extends OneHandedTestCase { @Test public void testOnStateChangedNone_removeViewAndAttachToWindow() { - when(mSpiedTutorialHandler.canShowTutorial()).thenReturn(true); + when(mSpiedTutorialHandler.isShowing()).thenReturn(true); try { mSpiedTutorialHandler.onStateChanged(STATE_NONE); } catch (ClassCastException e) { @@ -110,19 +101,19 @@ public class OneHandedTutorialHandlerTest extends OneHandedTestCase { @Test public void testOnStateChangedNone_shouldNotAttachWindow() { - when(mSpiedTutorialHandler.canShowTutorial()).thenReturn(true); + when(mSpiedTutorialHandler.isShowing()).thenReturn(true); try { mSpiedTutorialHandler.onStateChanged(STATE_NONE); } catch (ClassCastException e) { // no-op, just assert setTutorialShownCountIncrement() never be called } - verify(mSpiedTutorialHandler, never()).setTutorialShownCountIncrement(); + verify(mSpiedTutorialHandler, never()).createViewAndAttachToWindow(any()); } @Test public void testOnConfigurationChanged_shouldUpdateViewContent() { - when(mSpiedTutorialHandler.canShowTutorial()).thenReturn(true); + when(mSpiedTutorialHandler.isShowing()).thenReturn(true); try { mSpiedTutorialHandler.onStateChanged(STATE_ENTERING); } catch (ClassCastException e) { diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatHintPopupTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatHintPopupTest.java index 9845d4650d20..10fd7d705967 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatHintPopupTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatHintPopupTest.java @@ -22,7 +22,6 @@ import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.verify; import android.content.res.Configuration; -import android.os.IBinder; import android.testing.AndroidTestingRunner; import android.view.LayoutInflater; import android.widget.Button; @@ -52,7 +51,7 @@ import org.mockito.MockitoAnnotations; public class SizeCompatHintPopupTest extends ShellTestCase { @Mock private SyncTransactionQueue mSyncTransactionQueue; - @Mock private IBinder mActivityToken; + @Mock private SizeCompatUIController.SizeCompatUICallback mCallback; @Mock private ShellTaskOrganizer.TaskListener mTaskListener; @Mock private DisplayLayout mDisplayLayout; @@ -64,8 +63,9 @@ public class SizeCompatHintPopupTest extends ShellTestCase { MockitoAnnotations.initMocks(this); final int taskId = 1; - mLayout = new SizeCompatUILayout(mSyncTransactionQueue, mContext, new Configuration(), - taskId, mActivityToken, mTaskListener, mDisplayLayout, false /* hasShownHint*/); + mLayout = new SizeCompatUILayout(mSyncTransactionQueue, mCallback, mContext, + new Configuration(), taskId, mTaskListener, mDisplayLayout, + false /* hasShownHint */); mHint = (SizeCompatHintPopup) LayoutInflater.from(mContext).inflate(R.layout.size_compat_mode_hint, null); mHint.inject(mLayout); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatRestartButtonTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatRestartButtonTest.java index 5a43925a5677..a20a5e9e8d91 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatRestartButtonTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatRestartButtonTest.java @@ -22,7 +22,6 @@ import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.verify; import android.content.res.Configuration; -import android.os.IBinder; import android.testing.AndroidTestingRunner; import android.view.LayoutInflater; import android.widget.ImageButton; @@ -51,8 +50,10 @@ import org.mockito.MockitoAnnotations; @SmallTest public class SizeCompatRestartButtonTest extends ShellTestCase { + private static final int TASK_ID = 1; + @Mock private SyncTransactionQueue mSyncTransactionQueue; - @Mock private IBinder mActivityToken; + @Mock private SizeCompatUIController.SizeCompatUICallback mCallback; @Mock private ShellTaskOrganizer.TaskListener mTaskListener; @Mock private DisplayLayout mDisplayLayout; @@ -63,9 +64,9 @@ public class SizeCompatRestartButtonTest extends ShellTestCase { public void setUp() { MockitoAnnotations.initMocks(this); - final int taskId = 1; - mLayout = new SizeCompatUILayout(mSyncTransactionQueue, mContext, new Configuration(), - taskId, mActivityToken, mTaskListener, mDisplayLayout, false /* hasShownHint*/); + mLayout = new SizeCompatUILayout(mSyncTransactionQueue, mCallback, mContext, + new Configuration(), TASK_ID, mTaskListener, mDisplayLayout, + false /* hasShownHint */); mButton = (SizeCompatRestartButton) LayoutInflater.from(mContext).inflate(R.layout.size_compat_ui, null); mButton.inject(mLayout); @@ -75,12 +76,11 @@ public class SizeCompatRestartButtonTest extends ShellTestCase { @Test public void testOnClick() { - doNothing().when(mLayout).onRestartButtonClicked(); - final ImageButton button = mButton.findViewById(R.id.size_compat_restart_button); button.performClick(); verify(mLayout).onRestartButtonClicked(); + verify(mCallback).onSizeCompatRestartButtonClicked(TASK_ID); } @Test diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatUIControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatUIControllerTest.java index 806a90b7832a..8839f58ea889 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatUIControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatUIControllerTest.java @@ -27,7 +27,6 @@ import static org.mockito.Mockito.verify; import android.content.Context; import android.content.res.Configuration; -import android.os.IBinder; import android.testing.AndroidTestingRunner; import androidx.test.filters.SmallTest; @@ -61,7 +60,6 @@ public class SizeCompatUIControllerTest extends ShellTestCase { private @Mock DisplayController mMockDisplayController; private @Mock DisplayLayout mMockDisplayLayout; private @Mock DisplayImeController mMockImeController; - private @Mock IBinder mMockActivityToken; private @Mock ShellTaskOrganizer.TaskListener mMockTaskListener; private @Mock SyncTransactionQueue mMockSyncQueue; private @Mock SizeCompatUILayout mMockLayout; @@ -77,8 +75,7 @@ public class SizeCompatUIControllerTest extends ShellTestCase { mMockImeController, mMockSyncQueue) { @Override SizeCompatUILayout createLayout(Context context, int displayId, int taskId, - Configuration taskConfig, IBinder activityToken, - ShellTaskOrganizer.TaskListener taskListener) { + Configuration taskConfig, ShellTaskOrganizer.TaskListener taskListener) { return mMockLayout; } }; @@ -97,21 +94,21 @@ public class SizeCompatUIControllerTest extends ShellTestCase { // Verify that the restart button is added with non-null size compat info. mController.onSizeCompatInfoChanged(DISPLAY_ID, TASK_ID, taskConfig, - mMockActivityToken, mMockTaskListener); + mMockTaskListener); verify(mController).createLayout(any(), eq(DISPLAY_ID), eq(TASK_ID), eq(taskConfig), - eq(mMockActivityToken), eq(mMockTaskListener)); + eq(mMockTaskListener)); // Verify that the restart button is updated with non-null new size compat info. final Configuration newTaskConfig = new Configuration(); mController.onSizeCompatInfoChanged(DISPLAY_ID, TASK_ID, newTaskConfig, - mMockActivityToken, mMockTaskListener); + mMockTaskListener); - verify(mMockLayout).updateSizeCompatInfo(taskConfig, mMockActivityToken, mMockTaskListener, + verify(mMockLayout).updateSizeCompatInfo(taskConfig, mMockTaskListener, false /* isImeShowing */); // Verify that the restart button is removed with null size compat info. - mController.onSizeCompatInfoChanged(DISPLAY_ID, TASK_ID, null, null, mMockTaskListener); + mController.onSizeCompatInfoChanged(DISPLAY_ID, TASK_ID, null, mMockTaskListener); verify(mMockLayout).release(); } @@ -120,7 +117,7 @@ public class SizeCompatUIControllerTest extends ShellTestCase { public void testOnDisplayRemoved() { final Configuration taskConfig = new Configuration(); mController.onSizeCompatInfoChanged(DISPLAY_ID, TASK_ID, taskConfig, - mMockActivityToken, mMockTaskListener); + mMockTaskListener); mController.onDisplayRemoved(DISPLAY_ID + 1); @@ -135,7 +132,7 @@ public class SizeCompatUIControllerTest extends ShellTestCase { public void testOnDisplayConfigurationChanged() { final Configuration taskConfig = new Configuration(); mController.onSizeCompatInfoChanged(DISPLAY_ID, TASK_ID, taskConfig, - mMockActivityToken, mMockTaskListener); + mMockTaskListener); final Configuration newTaskConfig = new Configuration(); mController.onDisplayConfigurationChanged(DISPLAY_ID + 1, newTaskConfig); @@ -151,7 +148,7 @@ public class SizeCompatUIControllerTest extends ShellTestCase { public void testChangeButtonVisibilityOnImeShowHide() { final Configuration taskConfig = new Configuration(); mController.onSizeCompatInfoChanged(DISPLAY_ID, TASK_ID, taskConfig, - mMockActivityToken, mMockTaskListener); + mMockTaskListener); mController.onImeVisibilityChanged(DISPLAY_ID, true /* isShowing */); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatUILayoutTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatUILayoutTest.java index f33cfe86224f..ee4c81547bbd 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatUILayoutTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatUILayoutTest.java @@ -21,20 +21,16 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; -import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.Mockito.clearInvocations; -import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import android.app.ActivityClient; import android.content.res.Configuration; import android.graphics.Rect; -import android.os.IBinder; import android.testing.AndroidTestingRunner; import android.view.DisplayInfo; import android.view.SurfaceControl; @@ -66,7 +62,7 @@ public class SizeCompatUILayoutTest extends ShellTestCase { private static final int TASK_ID = 1; @Mock private SyncTransactionQueue mSyncTransactionQueue; - @Mock private IBinder mActivityToken; + @Mock private SizeCompatUIController.SizeCompatUICallback mCallback; @Mock private ShellTaskOrganizer.TaskListener mTaskListener; @Mock private DisplayLayout mDisplayLayout; @Mock private SizeCompatRestartButton mButton; @@ -80,8 +76,9 @@ public class SizeCompatUILayoutTest extends ShellTestCase { MockitoAnnotations.initMocks(this); mTaskConfig = new Configuration(); - mLayout = new SizeCompatUILayout(mSyncTransactionQueue, mContext, new Configuration(), - TASK_ID, mActivityToken, mTaskListener, mDisplayLayout, false /* hasShownHint*/); + mLayout = new SizeCompatUILayout(mSyncTransactionQueue, mCallback, mContext, + new Configuration(), TASK_ID, mTaskListener, mDisplayLayout, + false /* hasShownHint */); spyOn(mLayout); spyOn(mLayout.mButtonWindowManager); @@ -145,7 +142,7 @@ public class SizeCompatUILayoutTest extends ShellTestCase { // No diff clearInvocations(mLayout); - mLayout.updateSizeCompatInfo(mTaskConfig, mActivityToken, mTaskListener, + mLayout.updateSizeCompatInfo(mTaskConfig, mTaskListener, false /* isImeShowing */); verify(mLayout, never()).updateButtonSurfacePosition(); @@ -156,7 +153,7 @@ public class SizeCompatUILayoutTest extends ShellTestCase { clearInvocations(mLayout); final ShellTaskOrganizer.TaskListener newTaskListener = mock( ShellTaskOrganizer.TaskListener.class); - mLayout.updateSizeCompatInfo(mTaskConfig, mActivityToken, newTaskListener, + mLayout.updateSizeCompatInfo(mTaskConfig, newTaskListener, false /* isImeShowing */); verify(mLayout).release(); @@ -166,7 +163,7 @@ public class SizeCompatUILayoutTest extends ShellTestCase { clearInvocations(mLayout); final Configuration newTaskConfiguration = new Configuration(); newTaskConfiguration.windowConfiguration.setBounds(new Rect(0, 1000, 0, 2000)); - mLayout.updateSizeCompatInfo(newTaskConfiguration, mActivityToken, newTaskListener, + mLayout.updateSizeCompatInfo(newTaskConfiguration, newTaskListener, false /* isImeShowing */); verify(mLayout).updateButtonSurfacePosition(); @@ -228,12 +225,9 @@ public class SizeCompatUILayoutTest extends ShellTestCase { @Test public void testOnRestartButtonClicked() { - spyOn(ActivityClient.getInstance()); - doNothing().when(ActivityClient.getInstance()).restartActivityProcessIfVisible(any()); - mLayout.onRestartButtonClicked(); - verify(ActivityClient.getInstance()).restartActivityProcessIfVisible(mActivityToken); + verify(mCallback).onSizeCompatRestartButtonClicked(TASK_ID); } @Test diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java index 90b5b37694c6..1a30f164f9a8 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java @@ -21,11 +21,13 @@ import static android.view.Display.DEFAULT_DISPLAY; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assume.assumeFalse; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.app.ActivityManager; +import android.os.SystemProperties; import android.view.SurfaceControl; import android.view.SurfaceSession; @@ -52,6 +54,9 @@ import org.mockito.MockitoAnnotations; @SmallTest @RunWith(AndroidJUnit4.class) public final class StageTaskListenerTests { + private static final boolean ENABLE_SHELL_TRANSITIONS = + SystemProperties.getBoolean("persist.debug.shell_transit", false); + @Mock private ShellTaskOrganizer mTaskOrganizer; @Mock private StageTaskListener.StageListenerCallbacks mCallbacks; @Mock private SyncTransactionQueue mSyncQueue; @@ -93,6 +98,8 @@ public final class StageTaskListenerTests { @Test public void testChildTaskAppeared() { + // With shell transitions, the transition manages status changes, so skip this test. + assumeFalse(ENABLE_SHELL_TRANSITIONS); final ActivityManager.RunningTaskInfo childTask = new TestRunningTaskInfoBuilder().setParentTaskId(mRootTask.taskId).build(); @@ -110,6 +117,8 @@ public final class StageTaskListenerTests { @Test public void testTaskVanished() { + // With shell transitions, the transition manages status changes, so skip this test. + assumeFalse(ENABLE_SHELL_TRANSITIONS); final ActivityManager.RunningTaskInfo childTask = new TestRunningTaskInfoBuilder().setParentTaskId(mRootTask.taskId).build(); mStageTaskListener.mRootTaskInfo = mRootTask; diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java index 5061b2369bb2..284f384a3d26 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java @@ -97,7 +97,8 @@ public class StartingSurfaceDrawerTests { // listen for addView mAddWindowForTask = taskId; mViewThemeResId = view.getContext().getThemeResId(); - return true; + // Do not wait for background color + return false; } @Override diff --git a/libs/androidfw/CursorWindow.cpp b/libs/androidfw/CursorWindow.cpp index 1b8db46c54b6..3527eeead1d5 100644 --- a/libs/androidfw/CursorWindow.cpp +++ b/libs/androidfw/CursorWindow.cpp @@ -62,7 +62,6 @@ status_t CursorWindow::create(const String8 &name, size_t inflatedSize, CursorWi window->clear(); window->updateSlotsData(); - LOG(DEBUG) << "Created: " << window->toString(); *outWindow = window; return OK; diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp index 0a232d6272bd..2c299fa32315 100644 --- a/libs/hwui/Android.bp +++ b/libs/hwui/Android.bp @@ -47,6 +47,7 @@ cc_defaults { "-DATRACE_TAG=ATRACE_TAG_VIEW", "-DLOG_TAG=\"OpenGLRenderer\"", "-Wall", + "-Wthread-safety", "-Wno-unused-parameter", "-Wunreachable-code", "-Werror", diff --git a/libs/hwui/JankTracker.cpp b/libs/hwui/JankTracker.cpp index dd977c32f531..34e5577066f9 100644 --- a/libs/hwui/JankTracker.cpp +++ b/libs/hwui/JankTracker.cpp @@ -99,7 +99,7 @@ JankTracker::JankTracker(ProfileDataContainer* globalData) mFrameIntervalLegacy = frameIntervalNanos; } -void JankTracker::calculateLegacyJank(FrameInfo& frame) { +void JankTracker::calculateLegacyJank(FrameInfo& frame) REQUIRES(mDataMutex) { // Fast-path for jank-free frames int64_t totalDuration = frame.duration(sFrameStart, FrameInfoIndex::SwapBuffersCompleted); if (mDequeueTimeForgivenessLegacy && frame[FrameInfoIndex::DequeueBufferDuration] > 500_us) { @@ -257,7 +257,7 @@ void JankTracker::finishFrame(FrameInfo& frame, std::unique_ptr<FrameMetricsRepo } } -void JankTracker::recomputeThresholds(int64_t frameBudget) { +void JankTracker::recomputeThresholds(int64_t frameBudget) REQUIRES(mDataMutex) { if (mThresholdsFrameBudget == frameBudget) { return; } @@ -308,7 +308,7 @@ void JankTracker::dumpFrames(int fd) { dprintf(fd, "\n---PROFILEDATA---\n\n"); } -void JankTracker::reset() { +void JankTracker::reset() REQUIRES(mDataMutex) { mFrames.clear(); mData->reset(); (*mGlobalData)->reset(); diff --git a/libs/hwui/JankTracker.h b/libs/hwui/JankTracker.h index 0d2574cb8640..bdb784dc8747 100644 --- a/libs/hwui/JankTracker.h +++ b/libs/hwui/JankTracker.h @@ -62,7 +62,7 @@ public: // Calculates the 'legacy' jank information, i.e. with outdated refresh rate information and // without GPU completion or deadlined information. void calculateLegacyJank(FrameInfo& frame); - void dumpStats(int fd) { dumpData(fd, &mDescription, mData.get()); } + void dumpStats(int fd) NO_THREAD_SAFETY_ANALYSIS { dumpData(fd, &mDescription, mData.get()); } void dumpFrames(int fd); void reset(); diff --git a/libs/hwui/ProfileDataContainer.cpp b/libs/hwui/ProfileDataContainer.cpp index 41afc0e04c8b..dd78847bdcd8 100644 --- a/libs/hwui/ProfileDataContainer.cpp +++ b/libs/hwui/ProfileDataContainer.cpp @@ -27,7 +27,7 @@ namespace android { namespace uirenderer { -void ProfileDataContainer::freeData() { +void ProfileDataContainer::freeData() REQUIRES(mJankDataMutex) { if (mIsMapped) { munmap(mData, sizeof(ProfileData)); } else { diff --git a/libs/hwui/ProfileDataContainer.h b/libs/hwui/ProfileDataContainer.h index a61b8dcf390e..7d1b46c3d678 100644 --- a/libs/hwui/ProfileDataContainer.h +++ b/libs/hwui/ProfileDataContainer.h @@ -37,8 +37,9 @@ public: void rotateStorage(); void switchStorageToAshmem(int ashmemfd); - ProfileData* get() { return mData; } - ProfileData* operator->() { return mData; } + ProfileData* get() NO_THREAD_SAFETY_ANALYSIS { return mData; } + + ProfileData* operator->() NO_THREAD_SAFETY_ANALYSIS { return mData; } std::mutex& getDataMutex() { return mJankDataMutex; } diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index 81cee6103d22..025be7b2b6c1 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -614,6 +614,7 @@ nsecs_t CanvasContext::draw() { mCurrentFrameInfo->markFrameCompleted(); mCurrentFrameInfo->set(FrameInfoIndex::GpuCompleted) = mCurrentFrameInfo->get(FrameInfoIndex::FrameCompleted); + std::scoped_lock lock(mFrameMetricsReporterMutex); mJankTracker.finishFrame(*mCurrentFrameInfo, mFrameMetricsReporter); } } @@ -638,12 +639,16 @@ void CanvasContext::cleanupResources() { } void CanvasContext::reportMetricsWithPresentTime() { - if (mFrameMetricsReporter == nullptr) { - return; - } + { // acquire lock + std::scoped_lock lock(mFrameMetricsReporterMutex); + if (mFrameMetricsReporter == nullptr) { + return; + } + } // release lock if (mNativeSurface == nullptr) { return; } + ATRACE_CALL(); FrameInfo* forthBehind; int64_t frameNumber; { // acquire lock @@ -665,7 +670,22 @@ void CanvasContext::reportMetricsWithPresentTime() { nullptr /*outReleaseTime*/); forthBehind->set(FrameInfoIndex::DisplayPresentTime) = presentTime; - mFrameMetricsReporter->reportFrameMetrics(forthBehind->data(), true /*hasPresentTime*/); + { // acquire lock + std::scoped_lock lock(mFrameMetricsReporterMutex); + if (mFrameMetricsReporter != nullptr) { + mFrameMetricsReporter->reportFrameMetrics(forthBehind->data(), true /*hasPresentTime*/); + } + } // release lock +} + +FrameInfo* CanvasContext::getFrameInfoFromLast4(uint64_t frameNumber) { + std::scoped_lock lock(mLast4FrameInfosMutex); + for (size_t i = 0; i < mLast4FrameInfos.size(); i++) { + if (mLast4FrameInfos[i].second == frameNumber) { + return mLast4FrameInfos[i].first; + } + } + return nullptr; } void CanvasContext::onSurfaceStatsAvailable(void* context, ASurfaceControl* control, @@ -679,22 +699,13 @@ void CanvasContext::onSurfaceStatsAvailable(void* context, ASurfaceControl* cont nsecs_t gpuCompleteTime = functions.getAcquireTimeFunc(stats); uint64_t frameNumber = functions.getFrameNumberFunc(stats); - FrameInfo* frameInfo = nullptr; - { - std::lock_guard(instance->mLast4FrameInfosMutex); - for (size_t i = 0; i < instance->mLast4FrameInfos.size(); i++) { - if (instance->mLast4FrameInfos[i].second == frameNumber) { - frameInfo = instance->mLast4FrameInfos[i].first; - break; - } - } - } + FrameInfo* frameInfo = instance->getFrameInfoFromLast4(frameNumber); if (frameInfo != nullptr) { frameInfo->set(FrameInfoIndex::FrameCompleted) = std::max(gpuCompleteTime, frameInfo->get(FrameInfoIndex::SwapBuffersCompleted)); frameInfo->set(FrameInfoIndex::GpuCompleted) = gpuCompleteTime; - std::lock_guard(instance->mFrameMetricsReporterMutex); + std::scoped_lock lock(instance->mFrameMetricsReporterMutex); instance->mJankTracker.finishFrame(*frameInfo, instance->mFrameMetricsReporter); } } diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index 85af3e4fb0b6..6dbfcc349d50 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -160,6 +160,7 @@ public: void setContentDrawBounds(const Rect& bounds) { mContentDrawBounds = bounds; } void addFrameMetricsObserver(FrameMetricsObserver* observer) { + std::scoped_lock lock(mFrameMetricsReporterMutex); if (mFrameMetricsReporter.get() == nullptr) { mFrameMetricsReporter.reset(new FrameMetricsReporter()); } @@ -168,10 +169,10 @@ public: } void removeFrameMetricsObserver(FrameMetricsObserver* observer) { + std::scoped_lock lock(mFrameMetricsReporterMutex); if (mFrameMetricsReporter.get() != nullptr) { mFrameMetricsReporter->removeObserver(observer); if (!mFrameMetricsReporter->hasObservers()) { - std::lock_guard lock(mFrameMetricsReporterMutex); mFrameMetricsReporter.reset(nullptr); } } @@ -245,6 +246,8 @@ private: */ void reportMetricsWithPresentTime(); + FrameInfo* getFrameInfoFromLast4(uint64_t frameNumber); + // The same type as Frame.mWidth and Frame.mHeight int32_t mLastFrameWidth = 0; int32_t mLastFrameHeight = 0; @@ -305,7 +308,8 @@ private: std::string mName; JankTracker mJankTracker; FrameInfoVisualizer mProfiler; - std::unique_ptr<FrameMetricsReporter> mFrameMetricsReporter; + std::unique_ptr<FrameMetricsReporter> mFrameMetricsReporter + GUARDED_BY(mFrameMetricsReporterMutex); std::mutex mFrameMetricsReporterMutex; std::set<RenderNode*> mPrefetchedLayers; diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index 09ebb40e7ad7..bd3ca5a80f96 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -73,6 +73,7 @@ import com.android.internal.util.Preconditions; import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -103,7 +104,7 @@ public class AudioManager { private static final AudioVolumeGroupChangeHandler sAudioAudioVolumeGroupChangedHandler = new AudioVolumeGroupChangeHandler(); - private static Context sContext; + private static WeakReference<Context> sContext; /** * Broadcast intent, a hint for applications that audio is about to become @@ -800,7 +801,7 @@ public class AudioManager { } else { mOriginalContext = context; } - sContext = context; + sContext = new WeakReference<>(context); } @UnsupportedAppUsage @@ -7256,23 +7257,27 @@ public class AudioManager { */ public static boolean hasHapticChannels(@Nullable Context context, @NonNull Uri uri) { Objects.requireNonNull(uri); + if (context != null) { return hasHapticChannelsImpl(context, uri); - } else if (sContext != null) { + } + + Context cachedContext = sContext.get(); + if (cachedContext != null) { if (DEBUG) { Log.d(TAG, "Try to use static context to query if having haptic channels"); } - return hasHapticChannelsImpl(sContext, uri); - } else { - // Try with audio service context, this may fail to get correct result. - if (DEBUG) { - Log.d(TAG, "Try to use audio service context to query if having haptic channels"); - } - try { - return getService().hasHapticChannels(uri); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return hasHapticChannelsImpl(cachedContext, uri); + } + + // Try with audio service context, this may fail to get correct result. + if (DEBUG) { + Log.d(TAG, "Try to use audio service context to query if having haptic channels"); + } + try { + return getService().hasHapticChannels(uri); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); } } diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java index 952bbf56d5fa..2ea745b44288 100644 --- a/media/java/android/media/tv/tuner/Tuner.java +++ b/media/java/android/media/tv/tuner/Tuner.java @@ -347,7 +347,6 @@ public class Tuner implements AutoCloseable { mHandler = createEventHandler(); } - mHandler = createEventHandler(); int[] clientId = new int[1]; ResourceClientProfile profile = new ResourceClientProfile(); profile.tvInputSessionId = tvInputSessionId; @@ -516,6 +515,8 @@ public class Tuner implements AutoCloseable { mDemuxHandle = null; } + mTunerResourceManager.unregisterClientProfile(mClientId); + } /** diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp index 657c9eff1034..3cf9b0370823 100644 --- a/media/jni/android_media_tv_Tuner.cpp +++ b/media/jni/android_media_tv_Tuner.cpp @@ -339,6 +339,12 @@ MediaEvent::~MediaEvent() { if (pC2Buffer != NULL) { pC2Buffer->unregisterOnDestroyNotify(&DestroyCallback, this); } + + if (mLinearBlockObj != NULL) { + env->DeleteWeakGlobalRef(mLinearBlockObj); + mLinearBlockObj = NULL; + } + mFilterClient = NULL; } @@ -2450,7 +2456,10 @@ static sp<JTuner> setTuner(JNIEnv *env, jobject thiz, const sp<JTuner> &tuner) { if (old != NULL) { old->decStrong(thiz); } - env->SetLongField(thiz, gFields.tunerContext, (jlong)tuner.get()); + + if (tuner != NULL) { + env->SetLongField(thiz, gFields.tunerContext, (jlong)tuner.get()); + } return old; } @@ -4042,6 +4051,7 @@ static jint android_media_tv_Tuner_open_demux(JNIEnv* env, jobject thiz, jint ha static jint android_media_tv_Tuner_close_tuner(JNIEnv* env, jobject thiz) { sp<JTuner> tuner = getTuner(env, thiz); + setTuner(env, thiz, NULL); return (jint) tuner->close(); } diff --git a/native/android/surface_control.cpp b/native/android/surface_control.cpp index 93a54445a033..693a027bd0e2 100644 --- a/native/android/surface_control.cpp +++ b/native/android/surface_control.cpp @@ -44,70 +44,14 @@ using Transaction = SurfaceComposerClient::Transaction; LOG_ALWAYS_FATAL_IF(!static_cast<const Rect&>(name).isValid(), \ "invalid arg passed as " #name " argument"); -static bool getWideColorSupport(const sp<SurfaceControl>& surfaceControl) { - sp<SurfaceComposerClient> client = surfaceControl->getClient(); - - const sp<IBinder> display = client->getInternalDisplayToken(); - if (display == nullptr) { - ALOGE("unable to get wide color support for disconnected internal display"); - return false; - } - - bool isWideColorDisplay = false; - status_t err = client->isWideColorDisplay(display, &isWideColorDisplay); - if (err) { - ALOGE("unable to get wide color support"); - return false; - } - return isWideColorDisplay; -} - -static bool getHdrSupport(const sp<SurfaceControl>& surfaceControl) { - sp<SurfaceComposerClient> client = surfaceControl->getClient(); - - const sp<IBinder> display = client->getInternalDisplayToken(); - if (display == nullptr) { - ALOGE("unable to get hdr capabilities for disconnected internal display"); - return false; - } - - ui::DynamicDisplayInfo info; - if (status_t err = client->getDynamicDisplayInfo(display, &info); err != NO_ERROR) { - ALOGE("unable to get hdr capabilities"); - return err; - } - - return !info.hdrCapabilities.getSupportedHdrTypes().empty(); -} - -static bool isDataSpaceValid(const sp<SurfaceControl>& surfaceControl, ADataSpace dataSpace) { - static_assert(static_cast<int>(ADATASPACE_UNKNOWN) == static_cast<int>(HAL_DATASPACE_UNKNOWN)); - static_assert(static_cast<int>(ADATASPACE_SCRGB_LINEAR) == static_cast<int>(HAL_DATASPACE_V0_SCRGB_LINEAR)); - static_assert(static_cast<int>(ADATASPACE_SRGB) == static_cast<int>(HAL_DATASPACE_V0_SRGB)); - static_assert(static_cast<int>(ADATASPACE_SCRGB) == static_cast<int>(HAL_DATASPACE_V0_SCRGB)); - static_assert(static_cast<int>(ADATASPACE_DISPLAY_P3) == static_cast<int>(HAL_DATASPACE_DISPLAY_P3)); - static_assert(static_cast<int>(ADATASPACE_BT2020_PQ) == static_cast<int>(HAL_DATASPACE_BT2020_PQ)); - - switch (static_cast<android_dataspace_t>(dataSpace)) { - case HAL_DATASPACE_UNKNOWN: - case HAL_DATASPACE_V0_SRGB: - return true; - // These data space need wide gamut support. - case HAL_DATASPACE_V0_SCRGB_LINEAR: - case HAL_DATASPACE_V0_SCRGB: - case HAL_DATASPACE_DISPLAY_P3: - return getWideColorSupport(surfaceControl); - // These data space need HDR support. - case HAL_DATASPACE_BT2020_PQ: - if (!getHdrSupport(surfaceControl)) { - ALOGE("Invalid dataspace - device does not support hdr"); - return false; - } - return true; - default: - return false; - } -} +static_assert(static_cast<int>(ADATASPACE_UNKNOWN) == static_cast<int>(HAL_DATASPACE_UNKNOWN)); +static_assert(static_cast<int>(ADATASPACE_SCRGB_LINEAR) == + static_cast<int>(HAL_DATASPACE_V0_SCRGB_LINEAR)); +static_assert(static_cast<int>(ADATASPACE_SRGB) == static_cast<int>(HAL_DATASPACE_V0_SRGB)); +static_assert(static_cast<int>(ADATASPACE_SCRGB) == static_cast<int>(HAL_DATASPACE_V0_SCRGB)); +static_assert(static_cast<int>(ADATASPACE_DISPLAY_P3) == + static_cast<int>(HAL_DATASPACE_DISPLAY_P3)); +static_assert(static_cast<int>(ADATASPACE_BT2020_PQ) == static_cast<int>(HAL_DATASPACE_BT2020_PQ)); Transaction* ASurfaceTransaction_to_Transaction(ASurfaceTransaction* aSurfaceTransaction) { return reinterpret_cast<Transaction*>(aSurfaceTransaction); @@ -580,10 +524,6 @@ void ASurfaceTransaction_setBufferDataSpace(ASurfaceTransaction* aSurfaceTransac CHECK_NOT_NULL(aSurfaceControl); sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl); - if (!isDataSpaceValid(surfaceControl, aDataSpace)) { - ALOGE("Failed to set buffer dataspace - invalid dataspace"); - return; - } Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction); transaction->setDataspace(surfaceControl, static_cast<ui::Dataspace>(aDataSpace)); } @@ -650,10 +590,6 @@ void ASurfaceTransaction_setColor(ASurfaceTransaction* aSurfaceTransaction, CHECK_NOT_NULL(aSurfaceControl); sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl); - if (!isDataSpaceValid(surfaceControl, dataspace)) { - ALOGE("Failed to set buffer dataspace - invalid dataspace"); - return; - } Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction); half3 color; diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java index 8b448877c15b..c24782e8b310 100644 --- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java +++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java @@ -317,6 +317,9 @@ public class CompanionDeviceDiscoveryService extends Service { } void onDeviceSelected(String callingPackage, String deviceAddress) { + if (callingPackage == null || deviceAddress == null) { + return; + } mServiceCallback.complete(new Association( getUserId(), deviceAddress, callingPackage, mRequest.getDeviceProfile(), false, System.currentTimeMillis())); diff --git a/packages/CtsShim/apk/arm/CtsShim.apk b/packages/CtsShim/apk/arm/CtsShim.apk Binary files differindex da4ae568d713..e88e1ba97ca7 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 214d5c2465da..f35732cec024 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 da4ae568d713..e88e1ba97ca7 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 b4c625f36510..3d9f749f4e48 100644 --- a/packages/CtsShim/apk/x86/CtsShimPriv.apk +++ b/packages/CtsShim/apk/x86/CtsShimPriv.apk diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseFragment.java b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseFragment.java index cfb12bc30b8a..eb8b59e3384f 100644 --- a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseFragment.java +++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseFragment.java @@ -16,6 +16,7 @@ package com.android.settingslib.collapsingtoolbar; +import android.os.Build; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; @@ -55,7 +56,9 @@ public abstract class CollapsingToolbarBaseFragment extends Fragment { @Nullable Bundle savedInstanceState) { final View view = inflater.inflate(R.layout.collapsing_toolbar_base_layout, container, false); - mCoordinatorLayout = view.findViewById(R.id.content_parent); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + mCoordinatorLayout = view.findViewById(R.id.content_parent); + } mCollapsingToolbarLayout = view.findViewById(R.id.collapsing_toolbar); mAppBarLayout = view.findViewById(R.id.app_bar); if (mCollapsingToolbarLayout != null) { diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml index 3b56ce72aa74..d9db99e4efca 100644 --- a/packages/SettingsLib/res/values-es/strings.xml +++ b/packages/SettingsLib/res/values-es/strings.xml @@ -452,8 +452,8 @@ <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="7703677921000858479">"Es posible que el tablet se apague pronto (<xliff:g id="LEVEL">%1$s</xliff:g>)"</string> <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="4374784375644214578">"Es posible que el dispositivo se apague pronto (<xliff:g id="LEVEL">%1$s</xliff:g>)"</string> <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string> - <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> hasta que esté completamente cargada"</string> - <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="TIME">%2$s</xliff:g> hasta que esté completamente cargada"</string> + <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> hasta la carga completa"</string> + <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="TIME">%2$s</xliff:g> hasta la carga completa"</string> <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> - Carga limitada temporalmente"</string> <string name="battery_info_status_unknown" msgid="268625384868401114">"Desconocido"</string> <string name="battery_info_status_charging" msgid="4279958015430387405">"Cargando"</string> diff --git a/packages/SettingsLib/res/values-eu/arrays.xml b/packages/SettingsLib/res/values-eu/arrays.xml index 4bce1fe750e9..945268867ed2 100644 --- a/packages/SettingsLib/res/values-eu/arrays.xml +++ b/packages/SettingsLib/res/values-eu/arrays.xml @@ -218,17 +218,17 @@ </string-array> <string-array name="overlay_display_devices_entries"> <item msgid="4497393944195787240">"Bat ere ez"</item> - <item msgid="8461943978957133391">"480 p"</item> - <item msgid="6923083594932909205">"480 p (segurua)"</item> - <item msgid="1226941831391497335">"720 p"</item> - <item msgid="7051983425968643928">"720 p (segurua)"</item> - <item msgid="7765795608738980305">"1080 p"</item> - <item msgid="8084293856795803592">"1080 p (segurua)"</item> + <item msgid="8461943978957133391">"480p"</item> + <item msgid="6923083594932909205">"480p (segurua)"</item> + <item msgid="1226941831391497335">"720p"</item> + <item msgid="7051983425968643928">"720p (segurua)"</item> + <item msgid="7765795608738980305">"1080p"</item> + <item msgid="8084293856795803592">"1080p (segurua)"</item> <item msgid="938784192903353277">"4K"</item> <item msgid="8612549335720461635">"4K (segurua)"</item> <item msgid="7322156123728520872">"4K (hobetua)"</item> <item msgid="7735692090314849188">"4K (hobetua, segurua)"</item> - <item msgid="7346816300608639624">"720 p, 1080 p (bi pantaila)"</item> + <item msgid="7346816300608639624">"720p, 1080p (bi pantaila)"</item> </string-array> <string-array name="enable_opengl_traces_entries"> <item msgid="4433736508877934305">"Bat ere ez"</item> diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml index 54d01765eea2..c4ba44925bef 100644 --- a/packages/SettingsLib/res/values-kn/strings.xml +++ b/packages/SettingsLib/res/values-kn/strings.xml @@ -341,7 +341,7 @@ <string name="show_hw_screen_updates" msgid="2021286231267747506">"\'ಅಪ್ಡೇಟ್ಗಳನ್ನು ವೀಕ್ಷಿಸಿ\' ತೋರಿಸಿ"</string> <string name="show_hw_screen_updates_summary" msgid="3539770072741435691">"ಬರೆದಾಗ ವಿಂಡೊದೊಳಗೆ ವೀಕ್ಷಣೆ ಫ್ಲ್ಯಾಶ್ ಮಾಡುತ್ತದೆ"</string> <string name="show_hw_layers_updates" msgid="5268370750002509767">"ಹಾರ್ಡ್ವೇರ್ ಲೇಯರ್ ಅಪ್ಡೇಟ್"</string> - <string name="show_hw_layers_updates_summary" msgid="5850955890493054618">"ಅವುಗಳು ನವೀಕರಿಸಿದಾಗ ಹಾರ್ಡ್ವೇರ್ ಲೇಯರ್ಗಳು ಹಸಿರು ಫ್ಲ್ಯಾಶ್ ಆಗುತ್ತದೆ"</string> + <string name="show_hw_layers_updates_summary" msgid="5850955890493054618">"ಅಪ್ಡೇಟ್ ಆದಾಗ ಹಾರ್ಡ್ವೇರ್ ಲೇಯರ್ಗಳು ಹಸಿರು ಬಣ್ಣದಲ್ಲಿ ಫ್ಲ್ಯಾಶ್ ಆಗುತ್ತದೆ"</string> <string name="debug_hw_overdraw" msgid="8944851091008756796">"GPU ಓವರ್ಡ್ರಾ ಡೀಬಗ್"</string> <string name="disable_overlays" msgid="4206590799671557143">"HW ಓವರ್ಲೇ ನಿಷ್ಕ್ರಿಯ"</string> <string name="disable_overlays_summary" msgid="1954852414363338166">"ಸ್ಕ್ರೀನ್ ಸಂಯೋಜನೆಗಾಗಿ ಯಾವಾಗಲೂ GPU ಬಳಸಿ"</string> diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml index 4933f4a0ac93..97ad0a0ef347 100644 --- a/packages/SettingsLib/res/values-ko/strings.xml +++ b/packages/SettingsLib/res/values-ko/strings.xml @@ -462,7 +462,7 @@ <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"무선 충전 중"</string> <string name="battery_info_status_discharging" msgid="6962689305413556485">"충전 안함"</string> <string name="battery_info_status_not_charging" msgid="3371084153747234837">"연결됨, 충전 중 아님"</string> - <string name="battery_info_status_full" msgid="1339002294876531312">"청구됨"</string> + <string name="battery_info_status_full" msgid="1339002294876531312">"충전됨"</string> <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"관리자가 제어"</string> <string name="disabled" msgid="8017887509554714950">"사용 안함"</string> <string name="external_source_trusted" msgid="1146522036773132905">"허용됨"</string> diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml index 06525e449061..5ed5f39e0ebd 100644 --- a/packages/SettingsLib/res/values-ms/strings.xml +++ b/packages/SettingsLib/res/values-ms/strings.xml @@ -458,7 +458,7 @@ <string name="battery_info_status_unknown" msgid="268625384868401114">"Tidak diketahui"</string> <string name="battery_info_status_charging" msgid="4279958015430387405">"Mengecas"</string> <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Mengecas dgn cepat"</string> - <string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Mengecas dgn prlahan"</string> + <string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Mengecas perlahan"</string> <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Mengecas tanpa wayar"</string> <string name="battery_info_status_discharging" msgid="6962689305413556485">"Tidak mengecas"</string> <string name="battery_info_status_not_charging" msgid="3371084153747234837">"Bersambung, tidak mengecas"</string> diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml index 49dd07e83416..fea9601952e9 100644 --- a/packages/SettingsLib/res/values-pl/strings.xml +++ b/packages/SettingsLib/res/values-pl/strings.xml @@ -235,8 +235,8 @@ <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Sparuj urządzenia przez Wi-Fi, skanując kod QR"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Połącz się z siecią Wi-Fi"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, debug, dev"</string> - <string name="bugreport_in_power" msgid="8664089072534638709">"Skrót do zgłoszenia błędu"</string> - <string name="bugreport_in_power_summary" msgid="1885529649381831775">"Pokaż w menu zasilania przycisk zgłaszania błędu"</string> + <string name="bugreport_in_power" msgid="8664089072534638709">"Skrót do zgłaszania błędów"</string> + <string name="bugreport_in_power_summary" msgid="1885529649381831775">"Pokazuj w menu zasilania przycisk zgłaszania błędów"</string> <string name="keep_screen_on" msgid="1187161672348797558">"Pozostaw włączony ekran"</string> <string name="keep_screen_on_summary" msgid="1510731514101925829">"Ekran nie będzie gaszony podczas ładowania telefonu"</string> <string name="bt_hci_snoop_log" msgid="7291287955649081448">"Włącz dziennik snoop Bluetooth HCI"</string> @@ -249,7 +249,7 @@ <string name="mock_location_app_not_set" msgid="6972032787262831155">"Nie ustawiono aplikacji do pozorowania lokalizacji"</string> <string name="mock_location_app_set" msgid="4706722469342913843">"Aplikacja do pozorowania lokalizacji: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="debug_networking_category" msgid="6829757985772659599">"Sieci"</string> - <string name="wifi_display_certification" msgid="1805579519992520381">"Wyświetlacz bezprzewodowy"</string> + <string name="wifi_display_certification" msgid="1805579519992520381">"Certyfikacja wyświetlacza bezprzewodowego"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Szczegółowy dziennik Wi-Fi"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Ograniczanie skanowania Wi-Fi"</string> <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Nietrwała randomizacja adresów MAC w sieci Wi-Fi"</string> @@ -281,7 +281,7 @@ <string name="private_dns_mode_provider" msgid="3619040641762557028">"Nazwa hosta dostawcy prywatnego DNS"</string> <string name="private_dns_mode_provider_hostname_hint" msgid="6564868953748514595">"Wpisz nazwę hosta dostawcy DNS"</string> <string name="private_dns_mode_provider_failure" msgid="8356259467861515108">"Nie udało się połączyć"</string> - <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Pokaż opcje certyfikacji wyświetlacza bezprzewodowego"</string> + <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Pokazuj opcje certyfikacji wyświetlacza bezprzewodowego"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Zwiększ poziom rejestrowania Wi‑Fi, pokazuj według RSSI SSID w selektorze Wi‑Fi"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Zmniejsza zużycie baterii i zwiększa wydajność sieci"</string> <string name="wifi_enhanced_mac_randomization_summary" msgid="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> @@ -297,9 +297,9 @@ <string name="select_usb_configuration_dialog_title" msgid="3579567144722589237">"Wybierz konfigurację USB"</string> <string name="allow_mock_location" msgid="2102650981552527884">"Pozorowanie lokalizacji"</string> <string name="allow_mock_location_summary" msgid="179780881081354579">"Zezwalaj na pozorowanie lokalizacji"</string> - <string name="debug_view_attributes" msgid="3539609843984208216">"Inspekcja wyświetlania atrybutu"</string> + <string name="debug_view_attributes" msgid="3539609843984208216">"Inspekcja atrybutu wyświetlania"</string> <string name="mobile_data_always_on_summary" msgid="1112156365594371019">"Nie wyłączaj transmisji danych przez sieć komórkową, nawet gdy aktywne jest połączenie Wi-Fi (aby szybko przełączać sieci)"</string> - <string name="tethering_hardware_offload_summary" msgid="7801345335142803029">"Użyj akceleracji sprzętowej tetheringu, jeśli jest dostępna"</string> + <string name="tethering_hardware_offload_summary" msgid="7801345335142803029">"Używaj akceleracji sprzętowej tetheringu, jeśli jest dostępna"</string> <string name="adb_warning_title" msgid="7708653449506485728">"Czy zezwalać na debugowanie USB?"</string> <string name="adb_warning_message" msgid="8145270656419669221">"Debugowanie USB jest przeznaczone wyłącznie do celów programistycznych. Może służyć do kopiowania danych między komputerem a urządzeniem, instalowania aplikacji na urządzeniu bez powiadamiania, a także odczytu danych dziennika."</string> <string name="adbwifi_warning_title" msgid="727104571653031865">"Zezwalać na debugowanie bezprzewodowe?"</string> @@ -307,8 +307,8 @@ <string name="adb_keys_warning_message" msgid="2968555274488101220">"Odwołać dostęp wszystkich poprzednio autoryzowanych komputerów do debugowania USB?"</string> <string name="dev_settings_warning_title" msgid="8251234890169074553">"Zezwolić na ustawienia programistyczne?"</string> <string name="dev_settings_warning_message" msgid="37741686486073668">"Te ustawienia są przeznaczone wyłącznie dla programistów. Ich użycie może spowodować uszkodzenie lub nieprawidłowe działanie urządzenia i zainstalowanych na nim aplikacji."</string> - <string name="verify_apps_over_usb_title" msgid="6031809675604442636">"Zweryfikuj aplikacje przez USB"</string> - <string name="verify_apps_over_usb_summary" msgid="1317933737581167839">"Sprawdź, czy aplikacje zainstalowane przez ADB/ADT nie zachowują się w szkodliwy sposób"</string> + <string name="verify_apps_over_usb_title" msgid="6031809675604442636">"Weryfikuj aplikacje przez USB"</string> + <string name="verify_apps_over_usb_summary" msgid="1317933737581167839">"Sprawdzaj, czy aplikacje zainstalowane przez ADB/ADT nie zachowują się w szkodliwy sposób"</string> <string name="bluetooth_show_devices_without_names_summary" msgid="780964354377854507">"Urządzenia Bluetooth będą wyświetlane bez nazw (tylko adresy MAC)"</string> <string name="bluetooth_disable_absolute_volume_summary" msgid="2006309932135547681">"Wyłącza Głośność bezwzględną Bluetooth, jeśli występują problemy z urządzeniami zdalnymi, np. zbyt duża głośność lub brak kontroli"</string> <string name="bluetooth_enable_gabeldorsche_summary" msgid="2054730331770712629">"Włącza funkcje Bluetooth Gabeldorsche"</string> @@ -349,17 +349,17 @@ <string name="enable_opengl_traces_title" msgid="4638773318659125196">"Włącz śledzenie OpenGL"</string> <string name="usb_audio_disable_routing" msgid="3367656923544254975">"Wyłącz kierowanie dźwiękowe USB"</string> <string name="usb_audio_disable_routing_summary" msgid="8768242894849534699">"Wyłącz autokierowanie do urządzeń peryferyjnych audio USB"</string> - <string name="debug_layout" msgid="1659216803043339741">"Pokaż granice układu"</string> - <string name="debug_layout_summary" msgid="8825829038287321978">"Pokaż granice przycięcia, marginesy itd."</string> + <string name="debug_layout" msgid="1659216803043339741">"Pokazuj granice układu"</string> + <string name="debug_layout_summary" msgid="8825829038287321978">"Pokazuj granice przycięcia, marginesy itd."</string> <string name="force_rtl_layout_all_locales" msgid="8690762598501599796">"Układ od prawej do lewej"</string> - <string name="force_rtl_layout_all_locales_summary" msgid="6663016859517239880">"Wymuś wszędzie układ ekranu od prawej do lewej"</string> + <string name="force_rtl_layout_all_locales_summary" msgid="6663016859517239880">"Wymuszaj układ ekranu od prawej do lewej dla wszystkich języków"</string> <string name="window_blurs" msgid="6831008984828425106">"Zezwól na rozmycie na poziomie okna"</string> - <string name="force_msaa" msgid="4081288296137775550">"Wymuś 4x MSAA"</string> - <string name="force_msaa_summary" msgid="9070437493586769500">"Włącz 4x MSAA w aplikacjach OpenGL ES 2.0"</string> + <string name="force_msaa" msgid="4081288296137775550">"Wymuszaj 4x MSAA"</string> + <string name="force_msaa_summary" msgid="9070437493586769500">"Włączaj 4x MSAA w aplikacjach OpenGL ES 2.0"</string> <string name="show_non_rect_clip" msgid="7499758654867881817">"Debuguj operacje przycinania nieprostokątnego"</string> <string name="track_frame_time" msgid="522674651937771106">"Profil renderowania HWUI"</string> <string name="enable_gpu_debug_layers" msgid="4986675516188740397">"Warstwy debugowania GPU"</string> - <string name="enable_gpu_debug_layers_summary" msgid="4921521407377170481">"Zezwól na ładowanie warstw debugowania GPU"</string> + <string name="enable_gpu_debug_layers_summary" msgid="4921521407377170481">"Zezwalaj na ładowanie warstw debugowania GPU"</string> <string name="enable_verbose_vendor_logging" msgid="1196698788267682072">"Włącz szczegółowe rejestrowanie dostawcy"</string> <string name="enable_verbose_vendor_logging_summary" msgid="5426292185780393708">"Dołączaj do raportów o błędach dodatkowe dane dostawcy dotyczące konkretnego urządzenia, które mogą zawierać dane prywatne oraz wykorzystywać więcej baterii lub pamięci."</string> <string name="window_animation_scale_title" msgid="5236381298376812508">"Skala animacji okna"</string> diff --git a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractWifiMacAddressPreferenceController.java b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractWifiMacAddressPreferenceController.java index b5f275b463f4..b7549ec060ef 100644 --- a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractWifiMacAddressPreferenceController.java +++ b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractWifiMacAddressPreferenceController.java @@ -19,6 +19,7 @@ package com.android.settingslib.deviceinfo; import android.annotation.SuppressLint; import android.content.Context; import android.net.ConnectivityManager; +import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.text.TextUtils; @@ -89,7 +90,7 @@ public abstract class AbstractWifiMacAddressPreferenceController macAddress = macAddresses[0]; } - if (TextUtils.isEmpty(macAddress)) { + if (TextUtils.isEmpty(macAddress) || macAddress.equals(WifiInfo.DEFAULT_MAC_ADDRESS)) { mWifiMacAddress.setSummary(R.string.status_unavailable); } else { mWifiMacAddress.setSummary(macAddress); diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index bc1d420eaa3d..1581e240e1d7 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -161,6 +161,7 @@ <uses-permission android:name="android.permission.READ_INPUT_STATE" /> <uses-permission android:name="android.permission.SET_ORIENTATION" /> <uses-permission android:name="android.permission.INSTALL_PACKAGES" /> + <uses-permission android:name="android.permission.INSTALL_PACKAGE_UPDATES" /> <uses-permission android:name="com.android.permission.USE_INSTALLER_V2" /> <uses-permission android:name="android.permission.INSTALL_TEST_ONLY_PACKAGE" /> <uses-permission android:name="com.android.permission.USE_SYSTEM_DATA_LOADERS" /> diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index 8963ddaece35..1b2aefcd6ff0 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -451,6 +451,7 @@ <!-- started from SensoryPrivacyService --> <activity android:name=".sensorprivacy.SensorUseStartedActivity" android:exported="true" + android:launchMode="singleTop" android:permission="android.permission.MANAGE_SENSOR_PRIVACY" android:theme="@style/Theme.SystemUI.Dialog.Alert" android:finishOnCloseSystemDialogs="true"> diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt index ac9298dc9e89..8505a6254b28 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt @@ -16,7 +16,6 @@ import android.graphics.RectF import android.graphics.drawable.GradientDrawable import android.os.Looper import android.os.RemoteException -import android.os.UserHandle import android.util.Log import android.util.MathUtils import android.view.IRemoteAnimationFinishedCallback @@ -32,19 +31,20 @@ import android.view.animation.PathInterpolator import com.android.internal.annotations.VisibleForTesting import com.android.internal.policy.ScreenDecorationsUtils import com.android.wm.shell.startingsurface.SplashscreenContentDrawer -import com.android.wm.shell.startingsurface.SplashscreenContentDrawer.SplashScreenWindowAttrs +import com.android.wm.shell.startingsurface.StartingSurface import kotlin.math.roundToInt +private const val TAG = "ActivityLaunchAnimator" + /** * A class that allows activities to be started in a seamless way from a view that is transforming * nicely into the starting window. */ class ActivityLaunchAnimator( private val keyguardHandler: KeyguardHandler, + private val startingSurface: StartingSurface?, context: Context ) { - private val TAG = this::class.java.simpleName - companion object { const val ANIMATION_DURATION = 500L private const val ANIMATION_DURATION_FADE_OUT_CONTENT = 150L @@ -233,11 +233,21 @@ class ActivityLaunchAnimator( /** * Return a [Controller] that will animate and expand [view] into the opening window. * - * Important: The view must be attached to the window when calling this function and - * during the animation. + * Important: The view must be attached to a [ViewGroup] when calling this function and + * during the animation. For safety, this method will return null when it is not. */ @JvmStatic - fun fromView(view: View, cujType: Int? = null): Controller { + fun fromView(view: View, cujType: Int? = null): Controller? { + if (view.parent !is ViewGroup) { + // TODO(b/192194319): Throw instead of just logging. + Log.wtf( + TAG, + "Skipping animation as view $view is not attached to a ViewGroup", + Exception() + ) + return null + } + return GhostedViewLaunchAnimatorController(view, cujType) } } @@ -474,7 +484,12 @@ class ActivityLaunchAnimator( // which is usually the same color of the app background. We first fade in this layer // to hide the expanding view, then we fade it out with SRC mode to draw a hole in the // launch container and reveal the opening window. - val windowBackgroundColor = extractSplashScreenBackgroundColor(window) + val windowBackgroundColor = if (startingSurface != null) { + startingSurface.getBackgroundColor(window.taskInfo) + } else { + Log.w(TAG, "No starting surface, defaulting to SystemBGColor") + SplashscreenContentDrawer.getSystemBGColor() + } val windowBackgroundLayer = GradientDrawable().apply { setColor(windowBackgroundColor) alpha = 0 @@ -553,36 +568,6 @@ class ActivityLaunchAnimator( animator.start() } - /** Extract the background color of the app splash screen. */ - private fun extractSplashScreenBackgroundColor(window: RemoteAnimationTarget): Int { - val taskInfo = window.taskInfo - val windowPackage = taskInfo.topActivity.packageName - val userId = taskInfo.userId - val windowContext = context.createPackageContextAsUser( - windowPackage, Context.CONTEXT_RESTRICTED, UserHandle.of(userId)) - val activityInfo = taskInfo.topActivityInfo - val splashScreenThemeName = packageManager.getSplashScreenTheme(windowPackage, userId) - val splashScreenThemeId = if (splashScreenThemeName != null) { - windowContext.resources.getIdentifier(splashScreenThemeName, null, null) - } else { - 0 - } - - val themeResId = when { - splashScreenThemeId != 0 -> splashScreenThemeId - activityInfo.themeResource != 0 -> activityInfo.themeResource - else -> com.android.internal.R.style.Theme_DeviceDefault_DayNight - } - - if (themeResId != windowContext.themeResId) { - windowContext.setTheme(themeResId) - } - - val windowAttrs = SplashScreenWindowAttrs() - SplashscreenContentDrawer.getWindowAttrs(windowContext, windowAttrs) - return SplashscreenContentDrawer.peekWindowBGColor(windowContext, windowAttrs) - } - private fun applyStateToWindow(window: RemoteAnimationTarget, state: State) { val screenBounds = window.screenSpaceBounds val centerX = (screenBounds.left + screenBounds.right) / 2f diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt index ffb7ab4eff7c..b4ffb3f6cf4e 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt @@ -9,6 +9,7 @@ import android.graphics.drawable.Drawable import android.graphics.drawable.GradientDrawable import android.graphics.drawable.InsetDrawable import android.graphics.drawable.LayerDrawable +import android.util.Log import android.view.GhostView import android.view.View import android.view.ViewGroup @@ -17,13 +18,15 @@ import android.widget.FrameLayout import com.android.internal.jank.InteractionJankMonitor import kotlin.math.min +private const val TAG = "GhostedViewLaunchAnimatorController" + /** * A base implementation of [ActivityLaunchAnimator.Controller] which creates a [ghost][GhostView] * of [ghostedView] as well as an expandable background view, which are drawn and animated instead * of the ghosted view. * - * Important: [ghostedView] must be attached to the window when calling this function and during the - * animation. + * Important: [ghostedView] must be attached to a [ViewGroup] when calling this function and during + * the animation. * * Note: Avoid instantiating this directly and call [ActivityLaunchAnimator.Controller.fromView] * whenever possible instead. @@ -113,6 +116,13 @@ open class GhostedViewLaunchAnimatorController( } override fun onLaunchAnimationStart(isExpandingFullyAbove: Boolean) { + if (ghostedView.parent !is ViewGroup) { + // This should usually not happen, but let's make sure we don't crash if the view was + // detached right before we started the animation. + Log.w(TAG, "Skipping animation as ghostedView is not attached to a ViewGroup") + return + } + backgroundView = FrameLayout(launchContainer.context) launchContainerOverlay.add(backgroundView) @@ -138,7 +148,7 @@ open class GhostedViewLaunchAnimatorController( progress: Float, linearProgress: Float ) { - val ghostView = this.ghostView!! + val ghostView = this.ghostView ?: return val backgroundView = this.backgroundView!! if (!state.visible) { @@ -173,6 +183,11 @@ open class GhostedViewLaunchAnimatorController( } override fun onLaunchAnimationEnd(isExpandingFullyAbove: Boolean) { + if (ghostView == null) { + // We didn't actually run the animation. + return + } + cujType?.let { InteractionJankMonitor.getInstance().end(it) } backgroundDrawable?.wrapped?.alpha = startBackgroundAlpha diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml index 29fcf577da89..28c61663bd4d 100644 --- a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml +++ b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml @@ -35,13 +35,13 @@ android:id="@+id/animatable_clock_view" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:gravity="center_horizontal" + android:layout_gravity="start" + android:gravity="start" android:textSize="@dimen/clock_text_size" android:fontFamily="@font/clock" - android:typeface="monospace" android:elegantTextHeight="false" android:singleLine="true" + android:fontFeatureSettings="pnum" chargeAnimationDelay="350" dozeWeight="200" lockScreenWeight="400" diff --git a/packages/SystemUI/res-keyguard/values-ky/strings.xml b/packages/SystemUI/res-keyguard/values-ky/strings.xml index c7a482909fec..ced155a37286 100644 --- a/packages/SystemUI/res-keyguard/values-ky/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ky/strings.xml @@ -85,7 +85,7 @@ <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Өтө көп графикалык ачкычты тартуу аракети болду"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"PIN-кодуңузду <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес тердиңиз. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> секунддан кийин дагы аракет кылып көрүңүз."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Сырсөзүңүздү <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес тердиңиз. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> секунддан кийин дагы аракет кылып көрүңүз."</string> - <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Кулпуну ачуучу графикалык ачкычты <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес тарттыңыз. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> секунддан кийин дагы аракет кылып көрүңүз."</string> + <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Түзмөктү ачуучу графикалык ачкычты <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес тарттыңыз. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> секунддан кийин дагы аракет кылып көрүңүз."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"SIM-картанын PIN-коду туура эмес. Эми түзмөктү бөгөттөн чыгаруу үчүн байланыш операторуңузга кайрылышыңыз керек."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="other">SIM-картанын PIN-коду туура эмес, сизде <xliff:g id="NUMBER_1">%d</xliff:g> аракет калды.</item> diff --git a/packages/SystemUI/res-keyguard/values-land/dimens.xml b/packages/SystemUI/res-keyguard/values-land/dimens.xml new file mode 100644 index 000000000000..6342b9c0c7f0 --- /dev/null +++ b/packages/SystemUI/res-keyguard/values-land/dimens.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2021, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> +<resources> + <dimen name="num_pad_row_margin_bottom">3dp</dimen> + <dimen name="keyguard_eca_top_margin">0dp</dimen> + <dimen name="keyguard_eca_bottom_margin">2dp</dimen> + <dimen name="keyguard_password_height">26dp</dimen> + <dimen name="num_pad_entry_row_margin_bottom">0dp</dimen> + + <!-- The size of PIN text in the PIN unlock method. --> + <integer name="scaled_password_text_size">26</integer> +</resources> diff --git a/packages/SystemUI/res-keyguard/values-sw360dp-land/dimens.xml b/packages/SystemUI/res-keyguard/values-sw360dp-land/dimens.xml index eb5843b5a1b7..f465be4f5228 100644 --- a/packages/SystemUI/res-keyguard/values-sw360dp-land/dimens.xml +++ b/packages/SystemUI/res-keyguard/values-sw360dp-land/dimens.xml @@ -23,4 +23,7 @@ <dimen name="keyguard_eca_bottom_margin">4dp</dimen> <dimen name="keyguard_password_height">50dp</dimen> <dimen name="num_pad_entry_row_margin_bottom">4dp</dimen> + + <!-- The size of PIN text in the PIN unlock method. --> + <integer name="scaled_password_text_size">40</integer> </resources> diff --git a/packages/SystemUI/res/anim/fp_to_unlock.xml b/packages/SystemUI/res/anim/fp_to_unlock.xml new file mode 100644 index 000000000000..a348208f48c7 --- /dev/null +++ b/packages/SystemUI/res/anim/fp_to_unlock.xml @@ -0,0 +1,171 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2021 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<animated-vector xmlns:aapt="http://schemas.android.com/aapt" xmlns:android="http://schemas.android.com/apk/res/android"> + <aapt:attr name="android:drawable"> + <vector android:height="65dp" android:width="46dp" android:viewportHeight="65" android:viewportWidth="46"> + <group android:name="_R_G"> + <group android:name="_R_G_L_1_G_N_7_T_0" android:translateX="-27" android:translateY="-17.5"> + <group android:name="_R_G_L_1_G" android:translateX="30.75" android:translateY="25.75"> + <path android:name="_R_G_L_1_G_D_0_P_0" android:strokeColor="#b7f29f" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2.5" android:strokeAlpha="1" android:pathData=" M27.52 38.98 C26.49,39.95 25.29,40.73 23.98,41.29 C23.17,41.65 22.31,41.91 21.41,42.07 C20.74,42.19 20.05,42.25 19.34,42.25 C18.44,42.25 17.56,42.15 16.72,41.96 C15.93,41.77 15.16,41.51 14.43,41.18 C13.23,40.63 12.13,39.88 11.16,38.98 " /> + <path android:name="_R_G_L_1_G_D_1_P_0" android:strokeColor="#b7f29f" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2.5" android:strokeAlpha="1" android:pathData=" M8.64 34.07 C7.89,31.97 7.89,29.85 7.89,29.85 C7.89,24.05 12.81,19.34 19.34,19.34 C25.87,19.34 30.8,24.05 30.8,29.85 C30.8,29.85 30.8,30.16 30.8,30.16 C30.8,32.32 29.04,34.07 26.89,34.07 C25.28,34.07 23.86,33.1 23.27,31.61 C23.27,31.61 21.96,28.34 21.96,28.34 C21.37,26.85 19.93,25.89 18.34,25.89 C16.18,25.89 14.43,27.64 14.43,29.8 C14.43,31.42 14.87,32.99 15.68,34.36 C16.22,35.26 16.93,36.08 17.77,36.75 C17.77,36.75 18.52,37.34 18.52,37.34 " /> + <path android:name="_R_G_L_1_G_D_2_P_0" android:strokeColor="#b7f29f" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2.5" android:strokeAlpha="1" android:pathData=" M6.25 19.34 C7.48,17.3 9.46,15.58 11.9,14.42 C12.93,13.94 14.03,13.55 15.2,13.27 C16.51,12.96 17.9,12.8 19.34,12.8 C20.77,12.8 22.14,12.96 23.45,13.26 C24.9,13.6 26.26,14.12 27.48,14.78 C29.6,15.92 31.32,17.5 32.43,19.34 " /> + <path android:name="_R_G_L_1_G_D_3_P_0" android:strokeColor="#b7f29f" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2.5" android:strokeAlpha="1" android:pathData=" M9.52 8.7 C10.98,7.91 12.58,7.28 14.28,6.86 C15.89,6.46 17.58,6.25 19.34,6.25 C21.06,6.25 22.72,6.45 24.3,6.83 C26.04,7.25 27.67,7.89 29.16,8.7 " /> + </group> + </group> + <group android:name="_R_G_L_0_G_N_7_T_0" android:translateX="-27" android:translateY="-17.5"> + <group android:name="_R_G_L_0_G" android:translateX="47.357" android:translateY="53.25" android:pivotX="2.75" android:pivotY="2.75" android:scaleX="1.41866" android:scaleY="1.41866"> + <path android:name="_R_G_L_0_G_D_0_P_0" android:fillColor="#b7f29f" android:fillAlpha="0" android:fillType="nonZero" android:pathData=" M2.75 5.25 C4.13,5.25 5.25,4.13 5.25,2.75 C5.25,1.37 4.13,0.25 2.75,0.25 C1.37,0.25 0.25,1.37 0.25,2.75 C0.25,4.13 1.37,5.25 2.75,5.25c " /> + </group> + </group> + </group> + <group android:name="time_group" /> + </vector> + </aapt:attr> + <target android:name="_R_G_L_1_G_D_0_P_0"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator android:propertyName="pathData" android:duration="107" android:startOffset="0" android:valueFrom="M27.52 38.98 C26.49,39.95 25.29,40.73 23.98,41.29 C23.17,41.65 22.31,41.91 21.41,42.07 C20.74,42.19 20.05,42.25 19.34,42.25 C18.44,42.25 17.56,42.15 16.72,41.96 C15.93,41.77 15.16,41.51 14.43,41.18 C13.23,40.63 12.13,39.88 11.16,38.98 " android:valueTo="M30.81 32.26 C30.56,32.49 30.27,38.76 29.96,38.9 C29.77,39.46 29.13,39.94 28.57,40.26 C28.15,40.51 26.93,40.65 26.4,40.65 C26.18,40.65 11.91,40.62 11.71,40.58 C10.68,40.53 9.06,39.79 8.89,38.88 C8.6,38.74 8.34,32.48 8.1,32.27 " android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.541,0 0.833,0.767 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="pathData" android:duration="143" android:startOffset="107" android:valueFrom="M30.81 32.26 C30.56,32.49 30.27,38.76 29.96,38.9 C29.77,39.46 29.13,39.94 28.57,40.26 C28.15,40.51 26.93,40.65 26.4,40.65 C26.18,40.65 11.91,40.62 11.71,40.58 C10.68,40.53 9.06,39.79 8.89,38.88 C8.6,38.74 8.34,32.48 8.1,32.27 " android:valueTo="M30.64 30.14 C30.64,30.14 30.64,38.14 30.64,38.14 C30.64,38.77 30.36,39.32 29.91,39.69 C29.57,39.97 29.12,40.14 28.64,40.14 C28.64,40.14 10.14,40.14 10.14,40.14 C9.04,40.14 8.14,39.25 8.14,38.14 C8.14,38.14 8.14,30.14 8.14,30.14 " android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.233 0.331,1 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + </set> + </aapt:attr> + </target> + <target android:name="_R_G_L_1_G_D_1_P_0"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator android:propertyName="strokeAlpha" android:duration="140" android:startOffset="0" android:valueFrom="1" android:valueTo="1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="strokeAlpha" android:duration="50" android:startOffset="140" android:valueFrom="1" android:valueTo="0" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + </set> + </aapt:attr> + </target> + <target android:name="_R_G_L_1_G_D_1_P_0"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator android:propertyName="pathData" android:duration="107" android:startOffset="0" android:valueFrom="M8.64 34.07 C7.89,31.97 7.89,29.85 7.89,29.85 C7.89,24.05 12.81,19.34 19.34,19.34 C25.87,19.34 30.8,24.05 30.8,29.85 C30.8,29.85 30.8,30.16 30.8,30.16 C30.8,32.32 29.04,34.07 26.89,34.07 C25.28,34.07 23.86,33.1 23.27,31.61 C23.27,31.61 21.96,28.34 21.96,28.34 C21.37,26.85 19.93,25.89 18.34,25.89 C16.18,25.89 14.43,27.64 14.43,29.8 C14.43,31.42 14.87,32.99 15.68,34.36 C16.22,35.26 16.93,36.08 17.77,36.75 C17.77,36.75 18.52,37.34 18.52,37.34 " android:valueTo="M18.93 32.18 C17.11,32.68 16.62,30.26 16.62,30.26 C16.62,28.78 17.81,27.59 19.39,27.59 C20.96,27.59 22.15,28.78 22.15,30.26 C22.15,30.26 22.15,30.34 22.15,30.34 C22.15,30.89 21.11,32.54 19.57,32.19 C19.19,32.1 20.48,31.09 20.34,30.71 C20.34,30.71 20.02,29.88 20.02,29.88 C19.88,29.5 19.53,29.25 19.15,29.25 C18.63,29.25 18,29.67 18,30.22 C18,30.57 18.06,31.08 18.32,31.51 C18.49,31.8 19.02,32.25 19.79,32.04 C20.41,31.7 20.38,31.36 20.38,31.36 " android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.541,0 0.833,0.767 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="pathData" android:duration="107" android:startOffset="107" android:valueFrom="M18.93 32.18 C17.11,32.68 16.62,30.26 16.62,30.26 C16.62,28.78 17.81,27.59 19.39,27.59 C20.96,27.59 22.15,28.78 22.15,30.26 C22.15,30.26 22.15,30.34 22.15,30.34 C22.15,30.89 21.11,32.54 19.57,32.19 C19.19,32.1 20.48,31.09 20.34,30.71 C20.34,30.71 20.02,29.88 20.02,29.88 C19.88,29.5 19.53,29.25 19.15,29.25 C18.63,29.25 18,29.67 18,30.22 C18,30.57 18.06,31.08 18.32,31.51 C18.49,31.8 19.02,32.25 19.79,32.04 C20.41,31.7 20.38,31.36 20.38,31.36 " android:valueTo="M19.42 31.53 C18.15,31.52 18.11,30.33 18.11,30.33 C18.11,29.59 18.66,28.98 19.4,28.98 C20.13,28.98 20.69,29.59 20.69,30.33 C20.69,30.33 20.69,30.37 20.69,30.37 C20.69,30.64 20.49,30.87 20.25,30.87 C20.07,30.87 19.91,30.74 19.84,30.55 C19.84,30.55 19.69,30.14 19.69,30.14 C19.63,29.94 19.46,29.82 19.28,29.82 C19.04,29.82 18.61,30.02 18.61,30.29 C18.61,30.43 18.6,30.75 18.76,31.03 C18.87,31.21 19.21,31.77 19.96,31.41 C20.69,31.01 20.69,30.34 20.69,30.34 " android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.233 0,1 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + </set> + </aapt:attr> + </target> + <target android:name="_R_G_L_1_G_D_2_P_0"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator android:propertyName="pathData" android:duration="250" android:startOffset="0" android:valueFrom="M6.25 19.34 C7.48,17.3 9.46,15.58 11.9,14.42 C12.93,13.94 14.03,13.55 15.2,13.27 C16.51,12.96 17.9,12.8 19.34,12.8 C20.77,12.8 22.14,12.96 23.45,13.26 C24.9,13.6 26.26,14.12 27.48,14.78 C29.6,15.92 31.32,17.5 32.43,19.34 " android:valueTo="M8.14 30.22 C8.14,30.22 8.14,22.22 8.14,22.22 C8.14,21.71 8.33,21.25 8.64,20.9 C9,20.48 9.54,20.22 10.14,20.22 C10.14,20.22 28.64,20.22 28.64,20.22 C29.75,20.22 30.64,21.11 30.64,22.22 C30.64,22.22 30.64,30.14 30.64,30.14 " android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.541,0 0.189,1 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + </set> + </aapt:attr> + </target> + <target android:name="_R_G_L_1_G_D_3_P_0"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator android:propertyName="pathData" android:duration="95" android:startOffset="0" android:valueFrom="M9.52 8.7 C10.98,7.91 12.58,7.28 14.28,6.86 C15.89,6.46 17.58,6.25 19.34,6.25 C21.06,6.25 22.72,6.45 24.3,6.83 C26.04,7.25 27.67,7.89 29.16,8.7 " android:valueTo="M11.47 14.84 C11.47,14.84 12.21,11.43 13.54,9.84 C14.84,8.28 16.68,7.22 19.35,7.22 C22.01,7.22 23.98,8.4 25.19,10.18 C26.39,11.96 27.25,14.84 27.25,14.84 " android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.541,0 0.833,0.767 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="pathData" android:duration="24" android:startOffset="95" android:valueFrom="M11.47 14.84 C11.47,14.84 12.21,11.43 13.54,9.84 C14.84,8.28 16.68,7.22 19.35,7.22 C22.01,7.22 23.98,8.4 25.19,10.18 C26.39,11.96 27.25,14.84 27.25,14.84 " android:valueTo="M12.11 16.85 C12.11,16.85 12.82,12.71 13.37,11.5 C14.17,9.24 16.38,7.53 19.35,7.53 C22.32,7.53 24.61,9.32 25.35,11.72 C25.61,12.64 26.62,16.85 26.62,16.85 " android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.233 0.833,0.767 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="pathData" android:duration="81" android:startOffset="119" android:valueFrom="M12.11 16.85 C12.11,16.85 12.82,12.71 13.37,11.5 C14.17,9.24 16.38,7.53 19.35,7.53 C22.32,7.53 24.61,9.32 25.35,11.72 C25.61,12.64 26.62,16.85 26.62,16.85 " android:valueTo="M13.12 20.04 C13.12,20.04 13.11,14.15 13.11,14.15 C13.11,10.77 15.91,8.04 19.36,8.04 C22.81,8.04 25.61,10.77 25.61,14.15 C25.61,14.15 25.62,20.04 25.62,20.04 " android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.233 0.261,1 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="pathData" android:duration="233" android:startOffset="200" android:valueFrom="M13.12 20.04 C13.12,20.04 13.11,14.15 13.11,14.15 C13.11,10.77 15.91,8.04 19.36,8.04 C22.81,8.04 25.61,10.77 25.61,14.15 C25.61,14.15 25.62,20.04 25.62,20.04 " android:valueTo="M37.91 20.05 C37.91,20.05 37.89,14.16 37.89,14.16 C37.89,10.79 35.15,8.05 31.86,8.03 C28.46,8.01 25.61,10.77 25.61,14.15 C25.61,14.15 25.62,20.04 25.62,20.04 " android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.123,0 0.23,1 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + </set> + </aapt:attr> + </target> + <target android:name="_R_G_L_0_G_D_0_P_0"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator android:propertyName="fillAlpha" android:duration="120" android:startOffset="0" android:valueFrom="0" android:valueTo="0" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="fillAlpha" android:duration="20" android:startOffset="120" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + </set> + </aapt:attr> + </target> + <target android:name="_R_G_L_0_G"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator android:propertyName="scaleX" android:duration="120" android:startOffset="0" android:valueFrom="1.4186600000000003" android:valueTo="1.4186600000000003" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0.43,1 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleY" android:duration="120" android:startOffset="0" android:valueFrom="1.4186600000000003" android:valueTo="1.4186600000000003" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0.43,1 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleX" android:duration="130" android:startOffset="120" android:valueFrom="1.4186600000000003" android:valueTo="1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0.43,1 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleY" android:duration="130" android:startOffset="120" android:valueFrom="1.4186600000000003" android:valueTo="1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0.43,1 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + </set> + </aapt:attr> + </target> + <target android:name="time_group"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator android:propertyName="translateX" android:duration="517" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType" /> + </set> + </aapt:attr> + </target> +</animated-vector>
\ No newline at end of file diff --git a/packages/SystemUI/res/anim/lock_to_unlock.xml b/packages/SystemUI/res/anim/lock_to_unlock.xml new file mode 100644 index 000000000000..ec51c0171709 --- /dev/null +++ b/packages/SystemUI/res/anim/lock_to_unlock.xml @@ -0,0 +1,163 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2021 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<animated-vector xmlns:aapt="http://schemas.android.com/aapt" xmlns:android="http://schemas.android.com/apk/res/android"> + <aapt:attr name="android:drawable"> + <vector android:height="65dp" android:width="46dp" android:viewportHeight="65" android:viewportWidth="46"> + <group android:name="_R_G"> + <group android:name="_R_G_L_2_G_N_10_N_11_T_0" android:translateX="-27.5" android:translateY="-17.5"> + <group android:name="_R_G_L_2_G_N_10_T_1" android:translateX="50.25" android:translateY="61"> + <group android:name="_R_G_L_2_G_N_10_T_0" android:translateX="-13.75" android:translateY="-7.5"> + <group android:name="_R_G_L_2_G" android:translateX="-0.375" android:translateY="-22.375"> + <path android:name="_R_G_L_2_G_D_0_P_0" android:strokeColor="#b7f29f" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2.5" android:strokeAlpha="1" android:pathData=" M4.75 15 C4.75,15 23.25,15 23.25,15 C24.35,15 25.25,15.9 25.25,17 C25.25,17 25.25,33 25.25,33 C25.25,34.1 24.35,35 23.25,35 C23.25,35 4.75,35 4.75,35 C3.65,35 2.75,34.1 2.75,33 C2.75,33 2.75,17 2.75,17 C2.75,15.9 3.65,15 4.75,15c " /> + </group> + </group> + </group> + </group> + <group android:name="_R_G_L_1_G_N_10_N_11_T_0" android:translateX="-27.5" android:translateY="-17.5"> + <group android:name="_R_G_L_1_G_N_10_T_1" android:translateX="50.25" android:translateY="61"> + <group android:name="_R_G_L_1_G_N_10_T_0" android:translateX="-13.75" android:translateY="-7.5"> + <group android:name="_R_G_L_1_G" android:translateX="5" android:translateY="-22.5"> + <path android:name="_R_G_L_1_G_D_0_P_0" android:strokeColor="#b7f29f" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2.5" android:strokeAlpha="1" android:pathData=" M2.5 15 C2.5,15 2.5,8.61 2.5,8.61 C2.5,5.24 5.3,2.5 8.75,2.5 C12.2,2.5 15,5.24 15,8.61 C15,8.61 15,15 15,15 " /> + </group> + </group> + </group> + </group> + <group android:name="_R_G_L_0_G_N_10_N_11_T_0" android:translateX="-27.5" android:translateY="-17.5"> + <group android:name="_R_G_L_0_G_N_10_T_1" android:translateX="50.25" android:translateY="61"> + <group android:name="_R_G_L_0_G_N_10_T_0" android:translateX="-13.75" android:translateY="-7.5"> + <group android:name="_R_G_L_0_G" android:translateX="11" android:translateY="-0.25" android:pivotX="2.75" android:pivotY="2.75" android:scaleX="1" android:scaleY="1"> + <path android:name="_R_G_L_0_G_D_0_P_0" android:fillColor="#b7f29f" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M2.75 5.25 C4.13,5.25 5.25,4.13 5.25,2.75 C5.25,1.37 4.13,0.25 2.75,0.25 C1.37,0.25 0.25,1.37 0.25,2.75 C0.25,4.13 1.37,5.25 2.75,5.25c " /> + </group> + </group> + </group> + </group> + </group> + <group android:name="time_group" /> + </vector> + </aapt:attr> + <target android:name="_R_G_L_2_G_N_10_T_1"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator android:propertyName="translateY" android:duration="133" android:startOffset="0" android:valueFrom="61" android:valueTo="57" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.369,0 0.6,1 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="translateY" android:duration="133" android:startOffset="133" android:valueFrom="57" android:valueTo="62.125" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.436,0 0.58,1 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="translateY" android:duration="100" android:startOffset="267" android:valueFrom="62.125" android:valueTo="61" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.449,0 0.469,1 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + </set> + </aapt:attr> + </target> + <target android:name="_R_G_L_1_G_D_0_P_0"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator android:propertyName="pathData" android:duration="67" android:startOffset="0" android:valueFrom="M2.5 15 C2.5,15 2.5,8.61 2.5,8.61 C2.5,5.24 5.3,2.5 8.75,2.5 C12.2,2.5 15,5.24 15,8.61 C15,8.61 15,15 15,15 " android:valueTo="M2.5 9.94 C2.5,9.94 2.5,3.55 2.5,3.55 C2.5,0.17 5.3,-2.56 8.75,-2.56 C12.2,-2.56 15,0.17 15,3.55 C15,3.55 15,15 15,15 " android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.552,0 0.453,1 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="pathData" android:duration="333" android:startOffset="67" android:valueFrom="M2.5 9.94 C2.5,9.94 2.5,3.55 2.5,3.55 C2.5,0.17 5.3,-2.56 8.75,-2.56 C12.2,-2.56 15,0.17 15,3.55 C15,3.55 15,15 15,15 " android:valueTo="M27.19 14.81 C27.19,14.81 27.19,8.3 27.19,8.3 C27.19,4.92 24.44,2.88 21.19,2.75 C17.74,2.62 15,4.74 15,8.11 C15,8.11 15,15 15,15 " android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.476,0 0.396,1 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + </set> + </aapt:attr> + </target> + <target android:name="_R_G_L_1_G_N_10_T_1"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator android:propertyName="translateY" android:duration="133" android:startOffset="0" android:valueFrom="61" android:valueTo="57" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.369,0 0.6,1 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="translateY" android:duration="133" android:startOffset="133" android:valueFrom="57" android:valueTo="62.125" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.436,0 0.58,1 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="translateY" android:duration="100" android:startOffset="267" android:valueFrom="62.125" android:valueTo="61" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.449,0 0.469,1 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + </set> + </aapt:attr> + </target> + <target android:name="_R_G_L_0_G"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator android:propertyName="scaleX" android:duration="100" android:startOffset="0" android:valueFrom="1" android:valueTo="0.8200000000000001" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.415,0 0.338,1 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleY" android:duration="100" android:startOffset="0" android:valueFrom="1" android:valueTo="0.8200000000000001" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.415,0 0.338,1 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleX" android:duration="283" android:startOffset="100" android:valueFrom="0.8200000000000001" android:valueTo="1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.249,0 0.529,1 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleY" android:duration="283" android:startOffset="100" android:valueFrom="0.8200000000000001" android:valueTo="1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.249,0 0.529,1 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + </set> + </aapt:attr> + </target> + <target android:name="_R_G_L_0_G_N_10_T_1"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator android:propertyName="translateY" android:duration="133" android:startOffset="0" android:valueFrom="61" android:valueTo="57" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.369,0 0.6,1 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="translateY" android:duration="133" android:startOffset="133" android:valueFrom="57" android:valueTo="62.125" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.436,0 0.58,1 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="translateY" android:duration="100" android:startOffset="267" android:valueFrom="62.125" android:valueTo="61" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.449,0 0.469,1 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + </set> + </aapt:attr> + </target> + <target android:name="time_group"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator android:propertyName="translateX" android:duration="517" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType" /> + </set> + </aapt:attr> + </target> +</animated-vector>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml index e40138e1f49c..9ce83a789f59 100644 --- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml +++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml @@ -52,6 +52,8 @@ android:paddingStart="@dimen/keyguard_indication_text_padding" android:paddingEnd="@dimen/keyguard_indication_text_padding" android:textAppearance="@style/TextAppearance.Keyguard.BottomArea" + android:maxLines="2" + android:ellipsize="end" android:alpha=".8" android:accessibilityLiveRegion="polite" android:visibility="gone"/> diff --git a/packages/SystemUI/res/layout/people_space_activity_no_conversations.xml b/packages/SystemUI/res/layout/people_space_activity_no_conversations.xml index e87bf61417db..2e9ff07caed9 100644 --- a/packages/SystemUI/res/layout/people_space_activity_no_conversations.xml +++ b/packages/SystemUI/res/layout/people_space_activity_no_conversations.xml @@ -15,6 +15,7 @@ --> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" android:id="@+id/top_level" android:layout_width="match_parent" android:layout_height="match_parent" @@ -55,7 +56,7 @@ android:background="@drawable/rounded_bg_full_large_radius" android:onClick="dismissActivity" android:text="@string/got_it" - android:textColor="?android:attr/textColorPrimary" + android:textColor="?androidprv:attr/textColorOnAccent" android:layout_marginBottom="60dp" android:layout_alignParentBottom="true" /> diff --git a/packages/SystemUI/res/layout/people_tile_medium_with_content.xml b/packages/SystemUI/res/layout/people_tile_medium_with_content.xml index 892f64b3123b..404365629aba 100644 --- a/packages/SystemUI/res/layout/people_tile_medium_with_content.xml +++ b/packages/SystemUI/res/layout/people_tile_medium_with_content.xml @@ -131,6 +131,7 @@ <TextView android:id="@+id/messages_count" android:gravity="end" + android:layout_marginStart="-32dp" android:paddingStart="8dp" android:paddingEnd="8dp" android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Notification.Title" @@ -147,6 +148,7 @@ android:id="@+id/predefined_icon" android:tint="?android:attr/textColorSecondary" android:gravity="end|center_vertical" + android:layout_marginStart="-24dp" android:layout_width="@dimen/regular_predefined_icon" android:layout_height="@dimen/regular_predefined_icon" /> </LinearLayout> diff --git a/packages/SystemUI/res/layout/rotate_suggestion.xml b/packages/SystemUI/res/layout/rotate_suggestion.xml index 194d2e063e97..1c3eedba4f6f 100644 --- a/packages/SystemUI/res/layout/rotate_suggestion.xml +++ b/packages/SystemUI/res/layout/rotate_suggestion.xml @@ -14,16 +14,19 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License --> - -<com.android.systemui.navigationbar.buttons.KeyButtonView - xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/rotate_suggestion" +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" - android:layout_weight="0" - android:scaleType="center" - android:visibility="invisible" - android:contentDescription="@string/accessibility_rotate_button" - android:paddingStart="@dimen/navigation_key_padding" - android:paddingEnd="@dimen/navigation_key_padding" -/>
\ No newline at end of file + > + + <com.android.systemui.navigationbar.buttons.KeyButtonView + android:id="@+id/rotate_suggestion" + android:layout_width="@dimen/floating_rotation_button_diameter" + android:layout_height="@dimen/floating_rotation_button_diameter" + android:contentDescription="@string/accessibility_rotate_button" + android:paddingStart="@dimen/navigation_key_padding" + android:paddingEnd="@dimen/navigation_key_padding" + android:layout_gravity="bottom|left" + android:scaleType="center" + android:visibility="invisible" /> +</FrameLayout>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml index fd60a00c3408..cf91a2b3e588 100644 --- a/packages/SystemUI/res/layout/status_bar_expanded.xml +++ b/packages/SystemUI/res/layout/status_bar_expanded.xml @@ -52,9 +52,12 @@ <include layout="@layout/dock_info_bottom_area_overlay" /> <com.android.keyguard.LockIconView + android:id="@+id/lock_icon_view" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:id="@+id/lock_icon_view" /> + android:padding="48px" + android:layout_gravity="center" + android:scaleType="centerCrop"/> <com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer android:layout_width="match_parent" diff --git a/packages/SystemUI/res/layout/udfps_keyguard_view.xml b/packages/SystemUI/res/layout/udfps_keyguard_view.xml index 33baa4e07dc7..8834ac040b54 100644 --- a/packages/SystemUI/res/layout/udfps_keyguard_view.xml +++ b/packages/SystemUI/res/layout/udfps_keyguard_view.xml @@ -30,16 +30,15 @@ android:visibility="gone"/> <!-- Fingerprint --> - <!-- AOD dashed fingerprint icon with moving dashes --> <com.airbnb.lottie.LottieAnimationView android:id="@+id/udfps_aod_fp" android:layout_width="match_parent" android:layout_height="match_parent" + android:padding="48px" android:layout_gravity="center" android:scaleType="centerCrop" app:lottie_autoPlay="false" - android:padding="16dp" app:lottie_loop="true" app:lottie_rawRes="@raw/udfps_aod_fp"/> @@ -48,10 +47,10 @@ android:id="@+id/udfps_lockscreen_fp" android:layout_width="match_parent" android:layout_height="match_parent" + android:padding="48px" android:layout_gravity="center" android:scaleType="centerCrop" app:lottie_autoPlay="false" app:lottie_loop="false" - android:padding="16dp" app:lottie_rawRes="@raw/udfps_lockscreen_fp"/> </com.android.systemui.biometrics.UdfpsKeyguardView> diff --git a/packages/SystemUI/res/raw/udfps_aod_fp.json b/packages/SystemUI/res/raw/udfps_aod_fp.json index cdac33244345..3247fe74fcfe 100644 --- a/packages/SystemUI/res/raw/udfps_aod_fp.json +++ b/packages/SystemUI/res/raw/udfps_aod_fp.json @@ -1,1095 +1,1324 @@ { - "v": "5.7.8", - "fr": 60, - "ip": 0, - "op": 361, - "w": 180, - "h": 185, - "nm": "fingerprint_burn_in_Loop", - "ddd": 0, - "assets": [], - "layers": [ + "v":"5.7.8", + "fr":60, + "ip":0, + "op":361, + "w":46, + "h":65, + "nm":"fingerprint_burn_in_Loop_02", + "ddd":0, + "assets":[ + + ], + "layers":[ { - "ddd": 0, - "ind": 1, - "ty": 4, - "nm": "Layer 1 Outlines 10", - "sr": 1, - "ks": { - "o": { - "a": 0, - "k": 100, - "ix": 11 + "ddd":0, + "ind":2, + "ty":4, + "nm":"Fingerprint_20210701 Outlines 9", + "sr":1, + "ks":{ + "o":{ + "a":0, + "k":100, + "ix":11 }, - "r": { - "a": 0, - "k": 0, - "ix": 10 + "r":{ + "a":0, + "k":0, + "ix":10 }, - "p": { - "a": 0, - "k": [ - 91.456, - 92.206, + "p":{ + "a":0, + "k":[ + 23.091, + 32.5, 0 ], - "ix": 2, - "l": 2 + "ix":2, + "l":2 }, - "a": { - "a": 0, - "k": [ - 20, - 25, + "a":{ + "a":0, + "k":[ + 19.341, + 24.25, 0 ], - "ix": 1, - "l": 2 + "ix":1, + "l":2 }, - "s": { - "a": 0, - "k": [ - 350, - 350, + "s":{ + "a":0, + "k":[ + 100, + 100, 100 ], - "ix": 6, - "l": 2 + "ix":6, + "l":2 } }, - "ao": 0, - "shapes": [ + "ao":0, + "shapes":[ { - "ty": "gr", - "it": [ + "ty":"gr", + "it":[ { - "ind": 0, - "ty": "sh", - "ix": 1, - "ks": { - "a": 0, - "k": { - "i": [ + "ind":0, + "ty":"sh", + "ix":1, + "ks":{ + "a":0, + "k":{ + "i":[ [ 0, 0 ], [ - -3.684, + -1.701, + 0.42 + ], + [ + -1.757, 0 ], [ - -2.883, - -1.583 + -1.577, + -0.381 + ], + [ + -1.485, + -0.816 ] ], - "o": [ + "o":[ + [ + 1.455, + -0.799 + ], [ - 2.883, - -1.583 + 1.608, + -0.397 ], [ - 3.683, + 1.719, 0 ], [ + 1.739, + 0.42 + ], + [ 0, 0 ] ], - "v": [ + "v":[ [ - -10.417, - 1.25 + -9.818, + 1.227 ], [ - 0.001, - -1.25 + -5.064, + -0.618 + ], + [ + 0, + -1.227 + ], + [ + 4.96, + -0.643 ], [ - 10.417, - 1.25 + 9.818, + 1.227 ] ], - "c": false + "c":false }, - "ix": 2 - }, - "nm": "Path 1", - "mn": "ADBE Vector Shape - Group", - "hd": false - }, - { - "ty": "tm", - "s": { - "a": 0, - "k": 0, - "ix": 1 - }, - "e": { - "a": 0, - "k": 17, - "ix": 2 - }, - "o": { - "a": 1, - "k": [ - { - "i": { - "x": [ - 0.833 - ], - "y": [ - 0.833 - ] - }, - "o": { - "x": [ - 0.167 - ], - "y": [ - 0.167 - ] - }, - "t": 0, - "s": [ - 246 - ] - }, - { - "t": 360, - "s": [ - 1326 - ] - } - ], - "ix": 3 + "ix":2 }, - "m": 1, - "ix": 2, - "nm": "Trim Paths 1", - "mn": "ADBE Vector Filter - Trim", - "hd": false + "nm":"Path 1", + "mn":"ADBE Vector Shape - Group", + "hd":false }, { - "ty": "st", - "c": { - "a": 0, - "k": [ + "ty":"st", + "c":{ + "a":0, + "k":[ 1, 1, 1, 1 ], - "ix": 3 - }, - "o": { - "a": 0, - "k": 100, - "ix": 4 - }, - "w": { - "a": 0, - "k": 1, - "ix": 5 - }, - "lc": 2, - "lj": 1, - "ml": 10, - "bm": 0, - "nm": "Stroke 1", - "mn": "ADBE Vector Graphic - Stroke", - "hd": false + "ix":3 + }, + "o":{ + "a":0, + "k":100, + "ix":4 + }, + "w":{ + "a":0, + "k":1, + "ix":5 + }, + "lc":2, + "lj":1, + "ml":10, + "bm":0, + "nm":"Stroke 1", + "mn":"ADBE Vector Graphic - Stroke", + "hd":false + }, + { + "ty":"tr", + "p":{ + "a":0, + "k":[ + 19.341, + 7.477 + ], + "ix":2 + }, + "a":{ + "a":0, + "k":[ + 0, + 0 + ], + "ix":1 + }, + "s":{ + "a":0, + "k":[ + 100, + 100 + ], + "ix":3 + }, + "r":{ + "a":0, + "k":0, + "ix":6 + }, + "o":{ + "a":0, + "k":100, + "ix":7 + }, + "sk":{ + "a":0, + "k":0, + "ix":4 + }, + "sa":{ + "a":0, + "k":0, + "ix":5 + }, + "nm":"Transform" + } + ], + "nm":"Top", + "np":2, + "cix":2, + "bm":0, + "ix":1, + "mn":"ADBE Vector Group", + "hd":false + }, + { + "ty":"tm", + "s":{ + "a":0, + "k":0, + "ix":1 + }, + "e":{ + "a":0, + "k":17, + "ix":2 + }, + "o":{ + "a":1, + "k":[ + { + "i":{ + "x":[ + 0.833 + ], + "y":[ + 0.833 + ] + }, + "o":{ + "x":[ + 0.167 + ], + "y":[ + 0.167 + ] + }, + "t":0, + "s":[ + 246 + ] + }, + { + "t":360, + "s":[ + 1326 + ] + } + ], + "ix":3 + }, + "m":1, + "ix":2, + "nm":"Trim Paths 1", + "mn":"ADBE Vector Filter - Trim", + "hd":false + }, + { + "ty":"gr", + "it":[ + { + "ty":"tm", + "s":{ + "a":0, + "k":0, + "ix":1 + }, + "e":{ + "a":0, + "k":17, + "ix":2 + }, + "o":{ + "a":0, + "k":0, + "ix":3 + }, + "m":1, + "ix":1, + "nm":"Trim Paths 1", + "mn":"ADBE Vector Filter - Trim", + "hd":false }, { - "ty": "tr", - "p": { - "a": 0, - "k": [ - 19.999, - 7.5 + "ty":"tr", + "p":{ + "a":0, + "k":[ + 0, + 0 ], - "ix": 2 + "ix":2 }, - "a": { - "a": 0, - "k": [ + "a":{ + "a":0, + "k":[ 0, 0 ], - "ix": 1 + "ix":1 }, - "s": { - "a": 0, - "k": [ + "s":{ + "a":0, + "k":[ 100, 100 ], - "ix": 3 + "ix":3 }, - "r": { - "a": 0, - "k": 0, - "ix": 6 + "r":{ + "a":0, + "k":0, + "ix":6 }, - "o": { - "a": 0, - "k": 100, - "ix": 7 + "o":{ + "a":0, + "k":100, + "ix":7 }, - "sk": { - "a": 0, - "k": 0, - "ix": 4 + "sk":{ + "a":0, + "k":0, + "ix":4 }, - "sa": { - "a": 0, - "k": 0, - "ix": 5 + "sa":{ + "a":0, + "k":0, + "ix":5 }, - "nm": "Transform" + "nm":"Transform" } ], - "nm": "Group 3", - "np": 3, - "cix": 2, - "bm": 0, - "ix": 1, - "mn": "ADBE Vector Group", - "hd": false + "nm":"Group 1", + "np":1, + "cix":2, + "bm":0, + "ix":3, + "mn":"ADBE Vector Group", + "hd":false } ], - "ip": 0, - "op": 600, - "st": 0, - "bm": 0 + "ip":0, + "op":600, + "st":0, + "bm":0 }, { - "ddd": 0, - "ind": 2, - "ty": 4, - "nm": "Layer 1 Outlines 5", - "sr": 1, - "ks": { - "o": { - "a": 0, - "k": 100, - "ix": 11 + "ddd":0, + "ind":3, + "ty":4, + "nm":"Fingerprint_20210701 Outlines 8", + "sr":1, + "ks":{ + "o":{ + "a":0, + "k":100, + "ix":11 }, - "r": { - "a": 0, - "k": 0, - "ix": 10 + "r":{ + "a":0, + "k":0, + "ix":10 }, - "p": { - "a": 0, - "k": [ - 91.456, - 92.206, + "p":{ + "a":0, + "k":[ + 23.091, + 32.5, 0 ], - "ix": 2, - "l": 2 + "ix":2, + "l":2 }, - "a": { - "a": 0, - "k": [ - 20, - 25, + "a":{ + "a":0, + "k":[ + 19.341, + 24.25, 0 ], - "ix": 1, - "l": 2 + "ix":1, + "l":2 }, - "s": { - "a": 0, - "k": [ - 350, - 350, + "s":{ + "a":0, + "k":[ + 100, + 100, 100 ], - "ix": 6, - "l": 2 + "ix":6, + "l":2 } }, - "ao": 0, - "shapes": [ + "ao":0, + "shapes":[ { - "ty": "gr", - "it": [ + "ty":"gr", + "it":[ { - "ind": 0, - "ty": "sh", - "ix": 1, - "ks": { - "a": 0, - "k": { - "i": [ + "ind":0, + "ty":"sh", + "ix":1, + "ks":{ + "a":0, + "k":{ + "i":[ [ 0, 0 ], [ - -3.684, + -1.701, + 0.42 + ], + [ + -1.757, 0 ], [ - -2.883, - -1.583 + -1.577, + -0.381 + ], + [ + -1.485, + -0.816 ] ], - "o": [ + "o":[ + [ + 1.455, + -0.799 + ], [ - 2.883, - -1.583 + 1.608, + -0.397 ], [ - 3.683, + 1.719, 0 ], [ + 1.739, + 0.42 + ], + [ 0, 0 ] ], - "v": [ + "v":[ [ - -10.417, - 1.25 + -9.818, + 1.227 ], [ - 0.001, - -1.25 + -5.064, + -0.618 + ], + [ + 0, + -1.227 + ], + [ + 4.96, + -0.643 ], [ - 10.417, - 1.25 + 9.818, + 1.227 ] ], - "c": false + "c":false }, - "ix": 2 + "ix":2 }, - "nm": "Path 1", - "mn": "ADBE Vector Shape - Group", - "hd": false + "nm":"Path 1", + "mn":"ADBE Vector Shape - Group", + "hd":false }, { - "ty": "tm", - "s": { - "a": 0, - "k": 0, - "ix": 1 - }, - "e": { - "a": 0, - "k": 54, - "ix": 2 - }, - "o": { - "a": 1, - "k": [ - { - "i": { - "x": [ - 0.833 - ], - "y": [ - 0.833 - ] - }, - "o": { - "x": [ - 0.167 - ], - "y": [ - 0.167 - ] - }, - "t": 0, - "s": [ - 0 - ] - }, - { - "t": 360, - "s": [ - 1080 - ] - } - ], - "ix": 3 - }, - "m": 1, - "ix": 2, - "nm": "Trim Paths 1", - "mn": "ADBE Vector Filter - Trim", - "hd": false - }, - { - "ty": "st", - "c": { - "a": 0, - "k": [ + "ty":"st", + "c":{ + "a":0, + "k":[ 1, 1, 1, 1 ], - "ix": 3 - }, - "o": { - "a": 0, - "k": 100, - "ix": 4 - }, - "w": { - "a": 0, - "k": 1, - "ix": 5 - }, - "lc": 2, - "lj": 1, - "ml": 10, - "bm": 0, - "nm": "Stroke 1", - "mn": "ADBE Vector Graphic - Stroke", - "hd": false + "ix":3 + }, + "o":{ + "a":0, + "k":100, + "ix":4 + }, + "w":{ + "a":0, + "k":1, + "ix":5 + }, + "lc":2, + "lj":1, + "ml":10, + "bm":0, + "nm":"Stroke 1", + "mn":"ADBE Vector Graphic - Stroke", + "hd":false }, { - "ty": "tr", - "p": { - "a": 0, - "k": [ - 19.999, - 7.5 + "ty":"tr", + "p":{ + "a":0, + "k":[ + 19.341, + 7.477 ], - "ix": 2 + "ix":2 }, - "a": { - "a": 0, - "k": [ + "a":{ + "a":0, + "k":[ 0, 0 ], - "ix": 1 + "ix":1 }, - "s": { - "a": 0, - "k": [ + "s":{ + "a":0, + "k":[ 100, 100 ], - "ix": 3 + "ix":3 }, - "r": { - "a": 0, - "k": 0, - "ix": 6 + "r":{ + "a":0, + "k":0, + "ix":6 }, - "o": { - "a": 0, - "k": 100, - "ix": 7 + "o":{ + "a":0, + "k":100, + "ix":7 }, - "sk": { - "a": 0, - "k": 0, - "ix": 4 + "sk":{ + "a":0, + "k":0, + "ix":4 }, - "sa": { - "a": 0, - "k": 0, - "ix": 5 + "sa":{ + "a":0, + "k":0, + "ix":5 }, - "nm": "Transform" + "nm":"Transform" } ], - "nm": "Group 3", - "np": 3, - "cix": 2, - "bm": 0, - "ix": 1, - "mn": "ADBE Vector Group", - "hd": false + "nm":"Top", + "np":2, + "cix":2, + "bm":0, + "ix":1, + "mn":"ADBE Vector Group", + "hd":false + }, + { + "ty":"tm", + "s":{ + "a":0, + "k":0, + "ix":1 + }, + "e":{ + "a":0, + "k":54, + "ix":2 + }, + "o":{ + "a":1, + "k":[ + { + "i":{ + "x":[ + 0.833 + ], + "y":[ + 0.833 + ] + }, + "o":{ + "x":[ + 0.167 + ], + "y":[ + 0.167 + ] + }, + "t":0, + "s":[ + 0 + ] + }, + { + "t":360, + "s":[ + 1080 + ] + } + ], + "ix":3 + }, + "m":1, + "ix":2, + "nm":"Trim Paths 1", + "mn":"ADBE Vector Filter - Trim", + "hd":false } ], - "ip": 0, - "op": 600, - "st": 0, - "bm": 0 + "ip":0, + "op":600, + "st":0, + "bm":0 }, { - "ddd": 0, - "ind": 3, - "ty": 4, - "nm": "Layer 1 Outlines 8", - "sr": 1, - "ks": { - "o": { - "a": 0, - "k": 100, - "ix": 11 + "ddd":0, + "ind":4, + "ty":4, + "nm":"Fingerprint_20210701 Outlines 7", + "sr":1, + "ks":{ + "o":{ + "a":0, + "k":100, + "ix":11 }, - "r": { - "a": 0, - "k": 0, - "ix": 10 + "r":{ + "a":0, + "k":0, + "ix":10 }, - "p": { - "a": 0, - "k": [ - 91.456, - 92.206, + "p":{ + "a":0, + "k":[ + 23.091, + 32.5, 0 ], - "ix": 2, - "l": 2 + "ix":2, + "l":2 }, - "a": { - "a": 0, - "k": [ - 20, - 25, + "a":{ + "a":0, + "k":[ + 19.341, + 24.25, 0 ], - "ix": 1, - "l": 2 + "ix":1, + "l":2 }, - "s": { - "a": 0, - "k": [ - 350, - 350, + "s":{ + "a":0, + "k":[ + 100, + 100, 100 ], - "ix": 6, - "l": 2 + "ix":6, + "l":2 } }, - "ao": 0, - "shapes": [ + "ao":0, + "shapes":[ { - "ty": "gr", - "it": [ + "ty":"gr", + "it":[ { - "ind": 0, - "ty": "sh", - "ix": 1, - "ks": { - "a": 0, - "k": { - "i": [ + "ind":0, + "ty":"sh", + "ix":1, + "ks":{ + "a":0, + "k":{ + "i":[ [ 0, 0 ], [ - -5.883, + -2.446, + 1.161 + ], + [ + -1.168, + 0.275 + ], + [ + -1.439, 0 ], [ - -2.367, - -3.933 + -1.301, + -0.304 + ], + [ + -1.225, + -0.66 + ], + [ + -1.11, + -1.844 ] ], - "o": [ + "o":[ + [ + 1.23, + -2.044 + ], [ - 2.367, - -3.933 + 1.024, + -0.486 ], [ - 5.883, + 1.312, + -0.31 + ], + [ + 1.425, 0 ], [ + 1.454, + 0.34 + ], + [ + 2.122, + 1.143 + ], + [ 0, 0 ] ], - "v": [ + "v":[ + [ + -13.091, + 3.273 + ], [ - -13.75, - 3.333 + -7.438, + -1.646 + ], + [ + -4.14, + -2.797 ], [ 0, - -3.333 + -3.273 + ], + [ + 4.104, + -2.805 ], [ - 13.75, - 3.333 + 8.141, + -1.29 + ], + [ + 13.091, + 3.273 ] ], - "c": false + "c":false }, - "ix": 2 - }, - "nm": "Path 1", - "mn": "ADBE Vector Shape - Group", - "hd": false - }, - { - "ty": "tm", - "s": { - "a": 0, - "k": 0, - "ix": 1 - }, - "e": { - "a": 0, - "k": 38.235, - "ix": 2 - }, - "o": { - "a": 1, - "k": [ - { - "i": { - "x": [ - 0.833 - ], - "y": [ - 0.833 - ] - }, - "o": { - "x": [ - 0.167 - ], - "y": [ - 0.167 - ] - }, - "t": 0, - "s": [ - 170 - ] - }, - { - "t": 360, - "s": [ - 890 - ] - } - ], - "ix": 3 + "ix":2 }, - "m": 1, - "ix": 2, - "nm": "Trim Paths 1", - "mn": "ADBE Vector Filter - Trim", - "hd": false + "nm":"Path 1", + "mn":"ADBE Vector Shape - Group", + "hd":false }, { - "ty": "st", - "c": { - "a": 0, - "k": [ + "ty":"st", + "c":{ + "a":0, + "k":[ 1, 1, 1, 1 ], - "ix": 3 - }, - "o": { - "a": 0, - "k": 100, - "ix": 4 - }, - "w": { - "a": 0, - "k": 1, - "ix": 5 - }, - "lc": 2, - "lj": 1, - "ml": 10, - "bm": 0, - "nm": "Stroke 1", - "mn": "ADBE Vector Graphic - Stroke", - "hd": false + "ix":3 + }, + "o":{ + "a":0, + "k":100, + "ix":4 + }, + "w":{ + "a":0, + "k":1, + "ix":5 + }, + "lc":2, + "lj":1, + "ml":10, + "bm":0, + "nm":"Stroke 1", + "mn":"ADBE Vector Graphic - Stroke", + "hd":false }, { - "ty": "tr", - "p": { - "a": 0, - "k": [ - 20, - 16.25 + "ty":"tr", + "p":{ + "a":0, + "k":[ + 19.341, + 16.069 ], - "ix": 2 + "ix":2 }, - "a": { - "a": 0, - "k": [ + "a":{ + "a":0, + "k":[ 0, 0 ], - "ix": 1 + "ix":1 }, - "s": { - "a": 0, - "k": [ + "s":{ + "a":0, + "k":[ 100, 100 ], - "ix": 3 + "ix":3 }, - "r": { - "a": 0, - "k": 0, - "ix": 6 + "r":{ + "a":0, + "k":0, + "ix":6 }, - "o": { - "a": 0, - "k": 100, - "ix": 7 + "o":{ + "a":0, + "k":100, + "ix":7 }, - "sk": { - "a": 0, - "k": 0, - "ix": 4 + "sk":{ + "a":0, + "k":0, + "ix":4 }, - "sa": { - "a": 0, - "k": 0, - "ix": 5 + "sa":{ + "a":0, + "k":0, + "ix":5 }, - "nm": "Transform" + "nm":"Transform" } ], - "nm": "Group 2", - "np": 3, - "cix": 2, - "bm": 0, - "ix": 1, - "mn": "ADBE Vector Group", - "hd": false + "nm":"Mid Top", + "np":2, + "cix":2, + "bm":0, + "ix":1, + "mn":"ADBE Vector Group", + "hd":false + }, + { + "ty":"tm", + "s":{ + "a":0, + "k":0, + "ix":1 + }, + "e":{ + "a":0, + "k":38.2, + "ix":2 + }, + "o":{ + "a":1, + "k":[ + { + "i":{ + "x":[ + 0.833 + ], + "y":[ + 0.833 + ] + }, + "o":{ + "x":[ + 0.167 + ], + "y":[ + 0.167 + ] + }, + "t":0, + "s":[ + 170 + ] + }, + { + "t":360, + "s":[ + 890 + ] + } + ], + "ix":3 + }, + "m":1, + "ix":2, + "nm":"Trim Paths 1", + "mn":"ADBE Vector Filter - Trim", + "hd":false } ], - "ip": 0, - "op": 600, - "st": 0, - "bm": 0 + "ip":0, + "op":600, + "st":0, + "bm":0 }, { - "ddd": 0, - "ind": 4, - "ty": 4, - "nm": "Layer 1 Outlines 4", - "sr": 1, - "ks": { - "o": { - "a": 0, - "k": 100, - "ix": 11 + "ddd":0, + "ind":5, + "ty":4, + "nm":"Fingerprint_20210701 Outlines 6", + "sr":1, + "ks":{ + "o":{ + "a":0, + "k":100, + "ix":11 }, - "r": { - "a": 0, - "k": 0, - "ix": 10 + "r":{ + "a":0, + "k":0, + "ix":10 }, - "p": { - "a": 0, - "k": [ - 91.456, - 92.206, + "p":{ + "a":0, + "k":[ + 23.091, + 32.5, 0 ], - "ix": 2, - "l": 2 + "ix":2, + "l":2 }, - "a": { - "a": 0, - "k": [ - 20, - 25, + "a":{ + "a":0, + "k":[ + 19.341, + 24.25, 0 ], - "ix": 1, - "l": 2 + "ix":1, + "l":2 }, - "s": { - "a": 0, - "k": [ - 350, - 350, + "s":{ + "a":0, + "k":[ + 100, + 100, 100 ], - "ix": 6, - "l": 2 + "ix":6, + "l":2 } }, - "ao": 0, - "shapes": [ + "ao":0, + "shapes":[ { - "ty": "gr", - "it": [ + "ty":"gr", + "it":[ { - "ind": 0, - "ty": "sh", - "ix": 1, - "ks": { - "a": 0, - "k": { - "i": [ + "ind":0, + "ty":"sh", + "ix":1, + "ks":{ + "a":0, + "k":{ + "i":[ [ 0, 0 ], [ - -5.883, + -2.446, + 1.161 + ], + [ + -1.168, + 0.275 + ], + [ + -1.439, 0 ], [ - -2.367, - -3.933 + -1.301, + -0.304 + ], + [ + -1.225, + -0.66 + ], + [ + -1.11, + -1.844 ] ], - "o": [ + "o":[ + [ + 1.23, + -2.044 + ], [ - 2.367, - -3.933 + 1.024, + -0.486 ], [ - 5.883, + 1.312, + -0.31 + ], + [ + 1.425, 0 ], [ + 1.454, + 0.34 + ], + [ + 2.122, + 1.143 + ], + [ 0, 0 ] ], - "v": [ + "v":[ + [ + -13.091, + 3.273 + ], + [ + -7.438, + -1.646 + ], [ - -13.75, - 3.333 + -4.14, + -2.797 ], [ 0, - -3.333 + -3.273 + ], + [ + 4.104, + -2.805 + ], + [ + 8.141, + -1.29 ], [ - 13.75, - 3.333 + 13.091, + 3.273 ] ], - "c": false + "c":false }, - "ix": 2 - }, - "nm": "Path 1", - "mn": "ADBE Vector Shape - Group", - "hd": false - }, - { - "ty": "tm", - "s": { - "a": 0, - "k": 0, - "ix": 1 - }, - "e": { - "a": 0, - "k": 34.235, - "ix": 2 - }, - "o": { - "a": 1, - "k": [ - { - "i": { - "x": [ - 0.833 - ], - "y": [ - 0.833 - ] - }, - "o": { - "x": [ - 0.167 - ], - "y": [ - 0.167 - ] - }, - "t": 0, - "s": [ - 0 - ] - }, - { - "t": 360, - "s": [ - 720 - ] - } - ], - "ix": 3 + "ix":2 }, - "m": 1, - "ix": 2, - "nm": "Trim Paths 1", - "mn": "ADBE Vector Filter - Trim", - "hd": false + "nm":"Path 1", + "mn":"ADBE Vector Shape - Group", + "hd":false }, { - "ty": "st", - "c": { - "a": 0, - "k": [ + "ty":"st", + "c":{ + "a":0, + "k":[ 1, 1, 1, 1 ], - "ix": 3 - }, - "o": { - "a": 0, - "k": 100, - "ix": 4 - }, - "w": { - "a": 0, - "k": 1, - "ix": 5 - }, - "lc": 2, - "lj": 1, - "ml": 10, - "bm": 0, - "nm": "Stroke 1", - "mn": "ADBE Vector Graphic - Stroke", - "hd": false + "ix":3 + }, + "o":{ + "a":0, + "k":100, + "ix":4 + }, + "w":{ + "a":0, + "k":1, + "ix":5 + }, + "lc":2, + "lj":1, + "ml":10, + "bm":0, + "nm":"Stroke 1", + "mn":"ADBE Vector Graphic - Stroke", + "hd":false }, { - "ty": "tr", - "p": { - "a": 0, - "k": [ - 20, - 16.25 + "ty":"tr", + "p":{ + "a":0, + "k":[ + 19.341, + 16.069 ], - "ix": 2 + "ix":2 }, - "a": { - "a": 0, - "k": [ + "a":{ + "a":0, + "k":[ 0, 0 ], - "ix": 1 + "ix":1 }, - "s": { - "a": 0, - "k": [ + "s":{ + "a":0, + "k":[ 100, 100 ], - "ix": 3 + "ix":3 }, - "r": { - "a": 0, - "k": 0, - "ix": 6 + "r":{ + "a":0, + "k":0, + "ix":6 }, - "o": { - "a": 0, - "k": 100, - "ix": 7 + "o":{ + "a":0, + "k":100, + "ix":7 }, - "sk": { - "a": 0, - "k": 0, - "ix": 4 + "sk":{ + "a":0, + "k":0, + "ix":4 }, - "sa": { - "a": 0, - "k": 0, - "ix": 5 + "sa":{ + "a":0, + "k":0, + "ix":5 }, - "nm": "Transform" + "nm":"Transform" } ], - "nm": "Group 2", - "np": 3, - "cix": 2, - "bm": 0, - "ix": 1, - "mn": "ADBE Vector Group", - "hd": false + "nm":"Mid Top", + "np":2, + "cix":2, + "bm":0, + "ix":1, + "mn":"ADBE Vector Group", + "hd":false + }, + { + "ty":"tm", + "s":{ + "a":0, + "k":0, + "ix":1 + }, + "e":{ + "a":0, + "k":34.2, + "ix":2 + }, + "o":{ + "a":1, + "k":[ + { + "i":{ + "x":[ + 0.833 + ], + "y":[ + 0.833 + ] + }, + "o":{ + "x":[ + 0.167 + ], + "y":[ + 0.167 + ] + }, + "t":0, + "s":[ + 0 + ] + }, + { + "t":360, + "s":[ + 720 + ] + } + ], + "ix":3 + }, + "m":1, + "ix":2, + "nm":"Trim Paths 1", + "mn":"ADBE Vector Filter - Trim", + "hd":false } ], - "ip": 0, - "op": 600, - "st": 0, - "bm": 0 + "ip":0, + "op":600, + "st":0, + "bm":0 }, { - "ddd": 0, - "ind": 5, - "ty": 4, - "nm": "Layer 1 Outlines 7", - "sr": 1, - "ks": { - "o": { - "a": 0, - "k": 100, - "ix": 11 + "ddd":0, + "ind":6, + "ty":4, + "nm":"Fingerprint_20210701 Outlines 5", + "sr":1, + "ks":{ + "o":{ + "a":0, + "k":100, + "ix":11 }, - "r": { - "a": 0, - "k": 0, - "ix": 10 + "r":{ + "a":0, + "k":0, + "ix":10 }, - "p": { - "a": 0, - "k": [ - 91.456, - 92.206, + "p":{ + "a":0, + "k":[ + 23.091, + 32.5, 0 ], - "ix": 2, - "l": 2 + "ix":2, + "l":2 }, - "a": { - "a": 0, - "k": [ - 20, - 25, + "a":{ + "a":0, + "k":[ + 19.341, + 24.25, 0 ], - "ix": 1, - "l": 2 + "ix":1, + "l":2 }, - "s": { - "a": 0, - "k": [ - 350, - 350, + "s":{ + "a":0, + "k":[ + 100, + 100, 100 ], - "ix": 6, - "l": 2 + "ix":6, + "l":2 } }, - "ao": 0, - "shapes": [ + "ao":0, + "shapes":[ { - "ty": "gr", - "it": [ + "ty":"gr", + "it":[ { - "ind": 0, - "ty": "sh", - "ix": 1, - "ks": { - "a": 0, - "k": { - "i": [ + "ind":0, + "ty":"sh", + "ix":1, + "ks":{ + "a":0, + "k":{ + "i":[ [ 0, 0 @@ -1099,61 +1328,61 @@ 0 ], [ - -6.65, + -6.53, 0 ], [ 0, - -5.9 + -5.793 ], [ 0, 0 ], [ - 2.333, + 2.159, 0 ], [ - 0.633, - 1.601 + 0.59, + 1.489 ], [ 0, 0 ], [ - 1.717, + 1.587, 0 ], [ 0, - 0 + -2.16 ], [ - 0, - -2.2 + -0.81, + -1.363 ], [ - -2.15, - -1.716 + -0.844, + -0.674 ], [ 0, 0 ] ], - "o": [ + "o":[ [ - -0.767, - -2.134 + -0.753, + -2.095 ], [ 0, - -5.917 + -5.793 ], [ - 6.65, + 6.529, 0 ], [ @@ -1162,10 +1391,10 @@ ], [ 0, - 2.333 + 2.16 ], [ - -1.734, + -1.604, 0 ], [ @@ -1173,20 +1402,20 @@ 0 ], [ - -0.634, - -1.599 + -0.589, + -1.489 ], [ - 0, + -2.161, 0 ], [ - -2.2, - 0 + 0, + 1.62 ], [ - 0, - 2.75 + 0.54, + 0.909 ], [ 0, @@ -1197,274 +1426,274 @@ 0 ] ], - "v": [ + "v":[ [ - -11.108, - 5.825 + -10.702, + 5.728 ], [ - -11.875, - 1.525 + -11.454, + 1.506 ], [ - -0.208, - -9.175 + 0.001, + -9 ], [ - 11.875, - 1.525 + 11.454, + 1.506 ], [ - 11.875, - 1.592 + 11.454, + 1.817 ], [ - 7.659, - 5.808 + 7.544, + 5.728 ], [ - 3.742, - 3.158 + 3.926, + 3.273 ], [ - 2.526, - 0.141 + 2.618, + 0 ], [ - -1.391, - -2.508 + -0.997, + -2.454 ], [ - -1.641, - -2.508 + -4.91, + 1.457 ], [ - -5.625, - 1.475 + -3.657, + 6.014 ], [ - -2.225, - 8.558 + -1.57, + 8.412 ], [ - -1.458, - 9.175 + -0.818, + 9 ] ], - "c": false + "c":false }, - "ix": 2 - }, - "nm": "Path 1", - "mn": "ADBE Vector Shape - Group", - "hd": false - }, - { - "ty": "tm", - "s": { - "a": 0, - "k": 0, - "ix": 1 - }, - "e": { - "a": 0, - "k": 35, - "ix": 2 - }, - "o": { - "a": 1, - "k": [ - { - "i": { - "x": [ - 0.833 - ], - "y": [ - 0.833 - ] - }, - "o": { - "x": [ - 0.167 - ], - "y": [ - 0.167 - ] - }, - "t": 0, - "s": [ - -159 - ] - }, - { - "t": 360, - "s": [ - 201 - ] - } - ], - "ix": 3 + "ix":2 }, - "m": 1, - "ix": 2, - "nm": "Trim Paths 1", - "mn": "ADBE Vector Filter - Trim", - "hd": false + "nm":"Path 1", + "mn":"ADBE Vector Shape - Group", + "hd":false }, { - "ty": "st", - "c": { - "a": 0, - "k": [ + "ty":"st", + "c":{ + "a":0, + "k":[ 1, 1, 1, 1 ], - "ix": 3 - }, - "o": { - "a": 0, - "k": 100, - "ix": 4 - }, - "w": { - "a": 0, - "k": 1, - "ix": 5 - }, - "lc": 2, - "lj": 1, - "ml": 4, - "bm": 0, - "nm": "Stroke 1", - "mn": "ADBE Vector Graphic - Stroke", - "hd": false + "ix":3 + }, + "o":{ + "a":0, + "k":100, + "ix":4 + }, + "w":{ + "a":0, + "k":1, + "ix":5 + }, + "lc":2, + "lj":1, + "ml":10, + "bm":0, + "nm":"Stroke 1", + "mn":"ADBE Vector Graphic - Stroke", + "hd":false }, { - "ty": "tr", - "p": { - "a": 0, - "k": [ - 19.992, - 28.758 + "ty":"tr", + "p":{ + "a":0, + "k":[ + 19.341, + 28.341 ], - "ix": 2 + "ix":2 }, - "a": { - "a": 0, - "k": [ + "a":{ + "a":0, + "k":[ 0, 0 ], - "ix": 1 + "ix":1 }, - "s": { - "a": 0, - "k": [ + "s":{ + "a":0, + "k":[ 100, 100 ], - "ix": 3 + "ix":3 }, - "r": { - "a": 0, - "k": 0, - "ix": 6 + "r":{ + "a":0, + "k":0, + "ix":6 }, - "o": { - "a": 0, - "k": 100, - "ix": 7 + "o":{ + "a":0, + "k":100, + "ix":7 }, - "sk": { - "a": 0, - "k": 0, - "ix": 4 + "sk":{ + "a":0, + "k":0, + "ix":4 }, - "sa": { - "a": 0, - "k": 0, - "ix": 5 + "sa":{ + "a":0, + "k":0, + "ix":5 }, - "nm": "Transform" + "nm":"Transform" } ], - "nm": "Group 4", - "np": 3, - "cix": 2, - "bm": 0, - "ix": 1, - "mn": "ADBE Vector Group", - "hd": false + "nm":"Inside to dot ", + "np":2, + "cix":2, + "bm":0, + "ix":1, + "mn":"ADBE Vector Group", + "hd":false + }, + { + "ty":"tm", + "s":{ + "a":0, + "k":0, + "ix":1 + }, + "e":{ + "a":0, + "k":35, + "ix":2 + }, + "o":{ + "a":1, + "k":[ + { + "i":{ + "x":[ + 0.833 + ], + "y":[ + 0.833 + ] + }, + "o":{ + "x":[ + 0.167 + ], + "y":[ + 0.167 + ] + }, + "t":0, + "s":[ + -159 + ] + }, + { + "t":360, + "s":[ + 201 + ] + } + ], + "ix":3 + }, + "m":1, + "ix":2, + "nm":"Trim Paths 1", + "mn":"ADBE Vector Filter - Trim", + "hd":false } ], - "ip": 0, - "op": 600, - "st": 0, - "bm": 0 + "ip":0, + "op":600, + "st":0, + "bm":0 }, { - "ddd": 0, - "ind": 6, - "ty": 4, - "nm": "Layer 1 Outlines 6", - "sr": 1, - "ks": { - "o": { - "a": 0, - "k": 100, - "ix": 11 + "ddd":0, + "ind":7, + "ty":4, + "nm":"Fingerprint_20210701 Outlines 4", + "sr":1, + "ks":{ + "o":{ + "a":0, + "k":100, + "ix":11 }, - "r": { - "a": 0, - "k": 0, - "ix": 10 + "r":{ + "a":0, + "k":0, + "ix":10 }, - "p": { - "a": 0, - "k": [ - 91.456, - 92.206, + "p":{ + "a":0, + "k":[ + 23.091, + 32.5, 0 ], - "ix": 2, - "l": 2 + "ix":2, + "l":2 }, - "a": { - "a": 0, - "k": [ - 20, - 25, + "a":{ + "a":0, + "k":[ + 19.341, + 24.25, 0 ], - "ix": 1, - "l": 2 + "ix":1, + "l":2 }, - "s": { - "a": 0, - "k": [ - 350, - 350, + "s":{ + "a":0, + "k":[ + 100, + 100, 100 ], - "ix": 6, - "l": 2 + "ix":6, + "l":2 } }, - "ao": 0, - "shapes": [ + "ao":0, + "shapes":[ { - "ty": "gr", - "it": [ + "ty":"gr", + "it":[ { - "ind": 0, - "ty": "sh", - "ix": 1, - "ks": { - "a": 0, - "k": { - "i": [ + "ind":0, + "ty":"sh", + "ix":1, + "ks":{ + "a":0, + "k":{ + "i":[ [ 0, 0 @@ -1474,61 +1703,61 @@ 0 ], [ - -6.65, + -6.53, 0 ], [ 0, - -5.9 + -5.793 ], [ 0, 0 ], [ - 2.333, + 2.159, 0 ], [ - 0.633, - 1.601 + 0.59, + 1.489 ], [ 0, 0 ], [ - 1.717, + 1.587, 0 ], [ 0, - 0 + -2.16 ], [ - 0, - -2.2 + -0.81, + -1.363 ], [ - -2.15, - -1.716 + -0.844, + -0.674 ], [ 0, 0 ] ], - "o": [ + "o":[ [ - -0.767, - -2.134 + -0.753, + -2.095 ], [ 0, - -5.917 + -5.793 ], [ - 6.65, + 6.529, 0 ], [ @@ -1537,10 +1766,10 @@ ], [ 0, - 2.333 + 2.16 ], [ - -1.734, + -1.604, 0 ], [ @@ -1548,20 +1777,20 @@ 0 ], [ - -0.634, - -1.599 + -0.589, + -1.489 ], [ - 0, + -2.161, 0 ], [ - -2.2, - 0 + 0, + 1.62 ], [ - 0, - 2.75 + 0.54, + 0.909 ], [ 0, @@ -1572,274 +1801,274 @@ 0 ] ], - "v": [ + "v":[ [ - -11.108, - 5.825 + -10.702, + 5.728 ], [ - -11.875, - 1.525 + -11.454, + 1.506 ], [ - -0.208, - -9.175 + 0.001, + -9 ], [ - 11.875, - 1.525 + 11.454, + 1.506 ], [ - 11.875, - 1.592 + 11.454, + 1.817 ], [ - 7.659, - 5.808 + 7.544, + 5.728 ], [ - 3.742, - 3.158 + 3.926, + 3.273 ], [ - 2.526, - 0.141 + 2.618, + 0 ], [ - -1.391, - -2.508 + -0.997, + -2.454 ], [ - -1.641, - -2.508 + -4.91, + 1.457 ], [ - -5.625, - 1.475 + -3.657, + 6.014 ], [ - -2.225, - 8.558 + -1.57, + 8.412 ], [ - -1.458, - 9.175 + -0.818, + 9 ] ], - "c": false + "c":false }, - "ix": 2 - }, - "nm": "Path 1", - "mn": "ADBE Vector Shape - Group", - "hd": false - }, - { - "ty": "tm", - "s": { - "a": 0, - "k": 0, - "ix": 1 - }, - "e": { - "a": 0, - "k": 9, - "ix": 2 - }, - "o": { - "a": 1, - "k": [ - { - "i": { - "x": [ - 0.833 - ], - "y": [ - 0.833 - ] - }, - "o": { - "x": [ - 0.167 - ], - "y": [ - 0.167 - ] - }, - "t": 0, - "s": [ - 135 - ] - }, - { - "t": 360, - "s": [ - 495 - ] - } - ], - "ix": 3 + "ix":2 }, - "m": 1, - "ix": 2, - "nm": "Trim Paths 1", - "mn": "ADBE Vector Filter - Trim", - "hd": false + "nm":"Path 1", + "mn":"ADBE Vector Shape - Group", + "hd":false }, { - "ty": "st", - "c": { - "a": 0, - "k": [ + "ty":"st", + "c":{ + "a":0, + "k":[ 1, 1, 1, 1 ], - "ix": 3 - }, - "o": { - "a": 0, - "k": 100, - "ix": 4 - }, - "w": { - "a": 0, - "k": 1, - "ix": 5 - }, - "lc": 2, - "lj": 1, - "ml": 4, - "bm": 0, - "nm": "Stroke 1", - "mn": "ADBE Vector Graphic - Stroke", - "hd": false + "ix":3 + }, + "o":{ + "a":0, + "k":100, + "ix":4 + }, + "w":{ + "a":0, + "k":1, + "ix":5 + }, + "lc":2, + "lj":1, + "ml":10, + "bm":0, + "nm":"Stroke 1", + "mn":"ADBE Vector Graphic - Stroke", + "hd":false }, { - "ty": "tr", - "p": { - "a": 0, - "k": [ - 19.992, - 28.758 + "ty":"tr", + "p":{ + "a":0, + "k":[ + 19.341, + 28.341 ], - "ix": 2 + "ix":2 }, - "a": { - "a": 0, - "k": [ + "a":{ + "a":0, + "k":[ 0, 0 ], - "ix": 1 + "ix":1 }, - "s": { - "a": 0, - "k": [ + "s":{ + "a":0, + "k":[ 100, 100 ], - "ix": 3 + "ix":3 }, - "r": { - "a": 0, - "k": 0, - "ix": 6 + "r":{ + "a":0, + "k":0, + "ix":6 }, - "o": { - "a": 0, - "k": 100, - "ix": 7 + "o":{ + "a":0, + "k":100, + "ix":7 }, - "sk": { - "a": 0, - "k": 0, - "ix": 4 + "sk":{ + "a":0, + "k":0, + "ix":4 }, - "sa": { - "a": 0, - "k": 0, - "ix": 5 + "sa":{ + "a":0, + "k":0, + "ix":5 }, - "nm": "Transform" + "nm":"Transform" } ], - "nm": "Group 4", - "np": 3, - "cix": 2, - "bm": 0, - "ix": 1, - "mn": "ADBE Vector Group", - "hd": false + "nm":"Inside to dot ", + "np":2, + "cix":2, + "bm":0, + "ix":1, + "mn":"ADBE Vector Group", + "hd":false + }, + { + "ty":"tm", + "s":{ + "a":0, + "k":0, + "ix":1 + }, + "e":{ + "a":0, + "k":9, + "ix":2 + }, + "o":{ + "a":1, + "k":[ + { + "i":{ + "x":[ + 0.833 + ], + "y":[ + 0.833 + ] + }, + "o":{ + "x":[ + 0.167 + ], + "y":[ + 0.167 + ] + }, + "t":0, + "s":[ + 135 + ] + }, + { + "t":360, + "s":[ + 495 + ] + } + ], + "ix":3 + }, + "m":1, + "ix":2, + "nm":"Trim Paths 1", + "mn":"ADBE Vector Filter - Trim", + "hd":false } ], - "ip": 0, - "op": 600, - "st": 0, - "bm": 0 + "ip":0, + "op":600, + "st":0, + "bm":0 }, { - "ddd": 0, - "ind": 7, - "ty": 4, - "nm": "Layer 1 Outlines 3", - "sr": 1, - "ks": { - "o": { - "a": 0, - "k": 100, - "ix": 11 + "ddd":0, + "ind":8, + "ty":4, + "nm":"Fingerprint_20210701 Outlines 3", + "sr":1, + "ks":{ + "o":{ + "a":0, + "k":100, + "ix":11 }, - "r": { - "a": 0, - "k": 0, - "ix": 10 + "r":{ + "a":0, + "k":0, + "ix":10 }, - "p": { - "a": 0, - "k": [ - 91.456, - 92.206, + "p":{ + "a":0, + "k":[ + 23.091, + 32.5, 0 ], - "ix": 2, - "l": 2 + "ix":2, + "l":2 }, - "a": { - "a": 0, - "k": [ - 20, - 25, + "a":{ + "a":0, + "k":[ + 19.341, + 24.25, 0 ], - "ix": 1, - "l": 2 + "ix":1, + "l":2 }, - "s": { - "a": 0, - "k": [ - 350, - 350, + "s":{ + "a":0, + "k":[ + 100, + 100, 100 ], - "ix": 6, - "l": 2 + "ix":6, + "l":2 } }, - "ao": 0, - "shapes": [ + "ao":0, + "shapes":[ { - "ty": "gr", - "it": [ + "ty":"gr", + "it":[ { - "ind": 0, - "ty": "sh", - "ix": 1, - "ks": { - "a": 0, - "k": { - "i": [ + "ind":0, + "ty":"sh", + "ix":1, + "ks":{ + "a":0, + "k":{ + "i":[ [ 0, 0 @@ -1849,61 +2078,61 @@ 0 ], [ - -6.65, + -6.53, 0 ], [ 0, - -5.9 + -5.793 ], [ 0, 0 ], [ - 2.333, + 2.159, 0 ], [ - 0.633, - 1.601 + 0.59, + 1.489 ], [ 0, 0 ], [ - 1.717, + 1.587, 0 ], [ 0, - 0 + -2.16 ], [ - 0, - -2.2 + -0.81, + -1.363 ], [ - -2.15, - -1.716 + -0.844, + -0.674 ], [ 0, 0 ] ], - "o": [ + "o":[ [ - -0.767, - -2.134 + -0.753, + -2.095 ], [ 0, - -5.917 + -5.793 ], [ - 6.65, + 6.529, 0 ], [ @@ -1912,10 +2141,10 @@ ], [ 0, - 2.333 + 2.16 ], [ - -1.734, + -1.604, 0 ], [ @@ -1923,20 +2152,20 @@ 0 ], [ - -0.634, - -1.599 + -0.589, + -1.489 ], [ - 0, + -2.161, 0 ], [ - -2.2, - 0 + 0, + 1.62 ], [ - 0, - 2.75 + 0.54, + 0.909 ], [ 0, @@ -1947,499 +2176,527 @@ 0 ] ], - "v": [ + "v":[ [ - -11.108, - 5.825 + -10.702, + 5.728 ], [ - -11.875, - 1.525 + -11.454, + 1.506 ], [ - -0.208, - -9.175 + 0.001, + -9 ], [ - 11.875, - 1.525 + 11.454, + 1.506 ], [ - 11.875, - 1.592 + 11.454, + 1.817 ], [ - 7.659, - 5.808 + 7.544, + 5.728 ], [ - 3.742, - 3.158 + 3.926, + 3.273 ], [ - 2.526, - 0.141 + 2.618, + 0 ], [ - -1.391, - -2.508 + -0.997, + -2.454 ], [ - -1.641, - -2.508 + -4.91, + 1.457 ], [ - -5.625, - 1.475 + -3.657, + 6.014 ], [ - -2.225, - 8.558 + -1.57, + 8.412 ], [ - -1.458, - 9.175 + -0.818, + 9 ] ], - "c": false + "c":false }, - "ix": 2 - }, - "nm": "Path 1", - "mn": "ADBE Vector Shape - Group", - "hd": false - }, - { - "ty": "tm", - "s": { - "a": 0, - "k": 0, - "ix": 1 - }, - "e": { - "a": 0, - "k": 30, - "ix": 2 - }, - "o": { - "a": 1, - "k": [ - { - "i": { - "x": [ - 0.833 - ], - "y": [ - 0.833 - ] - }, - "o": { - "x": [ - 0.167 - ], - "y": [ - 0.167 - ] - }, - "t": 0, - "s": [ - 0 - ] - }, - { - "t": 360, - "s": [ - 360 - ] - } - ], - "ix": 3 + "ix":2 }, - "m": 1, - "ix": 2, - "nm": "Trim Paths 1", - "mn": "ADBE Vector Filter - Trim", - "hd": false + "nm":"Path 1", + "mn":"ADBE Vector Shape - Group", + "hd":false }, { - "ty": "st", - "c": { - "a": 0, - "k": [ + "ty":"st", + "c":{ + "a":0, + "k":[ 1, 1, 1, 1 ], - "ix": 3 - }, - "o": { - "a": 0, - "k": 100, - "ix": 4 - }, - "w": { - "a": 0, - "k": 1, - "ix": 5 - }, - "lc": 2, - "lj": 1, - "ml": 4, - "bm": 0, - "nm": "Stroke 1", - "mn": "ADBE Vector Graphic - Stroke", - "hd": false + "ix":3 + }, + "o":{ + "a":0, + "k":100, + "ix":4 + }, + "w":{ + "a":0, + "k":1, + "ix":5 + }, + "lc":2, + "lj":1, + "ml":10, + "bm":0, + "nm":"Stroke 1", + "mn":"ADBE Vector Graphic - Stroke", + "hd":false }, { - "ty": "tr", - "p": { - "a": 0, - "k": [ - 19.992, - 28.758 + "ty":"tr", + "p":{ + "a":0, + "k":[ + 19.341, + 28.341 ], - "ix": 2 + "ix":2 }, - "a": { - "a": 0, - "k": [ + "a":{ + "a":0, + "k":[ 0, 0 ], - "ix": 1 + "ix":1 }, - "s": { - "a": 0, - "k": [ + "s":{ + "a":0, + "k":[ 100, 100 ], - "ix": 3 + "ix":3 }, - "r": { - "a": 0, - "k": 0, - "ix": 6 + "r":{ + "a":0, + "k":0, + "ix":6 }, - "o": { - "a": 0, - "k": 100, - "ix": 7 + "o":{ + "a":0, + "k":100, + "ix":7 }, - "sk": { - "a": 0, - "k": 0, - "ix": 4 + "sk":{ + "a":0, + "k":0, + "ix":4 }, - "sa": { - "a": 0, - "k": 0, - "ix": 5 + "sa":{ + "a":0, + "k":0, + "ix":5 }, - "nm": "Transform" + "nm":"Transform" } ], - "nm": "Group 4", - "np": 3, - "cix": 2, - "bm": 0, - "ix": 1, - "mn": "ADBE Vector Group", - "hd": false + "nm":"Inside to dot ", + "np":2, + "cix":2, + "bm":0, + "ix":1, + "mn":"ADBE Vector Group", + "hd":false + }, + { + "ty":"tm", + "s":{ + "a":0, + "k":0, + "ix":1 + }, + "e":{ + "a":0, + "k":30, + "ix":2 + }, + "o":{ + "a":1, + "k":[ + { + "i":{ + "x":[ + 0.833 + ], + "y":[ + 0.833 + ] + }, + "o":{ + "x":[ + 0.167 + ], + "y":[ + 0.167 + ] + }, + "t":0, + "s":[ + 0 + ] + }, + { + "t":360, + "s":[ + 360 + ] + } + ], + "ix":3 + }, + "m":1, + "ix":2, + "nm":"Trim Paths 1", + "mn":"ADBE Vector Filter - Trim", + "hd":false } ], - "ip": 0, - "op": 600, - "st": 0, - "bm": 0 + "ip":0, + "op":600, + "st":0, + "bm":0 }, { - "ddd": 0, - "ind": 8, - "ty": 4, - "nm": "Layer 1 Outlines 2", - "sr": 1, - "ks": { - "o": { - "a": 0, - "k": 100, - "ix": 11 + "ddd":0, + "ind":9, + "ty":4, + "nm":"Fingerprint_20210701 Outlines", + "sr":1, + "ks":{ + "o":{ + "a":0, + "k":100, + "ix":11 }, - "r": { - "a": 0, - "k": 0, - "ix": 10 + "r":{ + "a":0, + "k":0, + "ix":10 }, - "p": { - "a": 0, - "k": [ - 91.456, - 92.206, + "p":{ + "a":0, + "k":[ + 23.091, + 32.5, 0 ], - "ix": 2, - "l": 2 + "ix":2, + "l":2 }, - "a": { - "a": 0, - "k": [ - 20, - 25, + "a":{ + "a":0, + "k":[ + 19.341, + 24.25, 0 ], - "ix": 1, - "l": 2 + "ix":1, + "l":2 }, - "s": { - "a": 0, - "k": [ - 350, - 350, + "s":{ + "a":0, + "k":[ + 100, + 100, 100 ], - "ix": 6, - "l": 2 + "ix":6, + "l":2 } }, - "ao": 0, - "shapes": [ + "ao":0, + "shapes":[ { - "ty": "gr", - "it": [ + "ty":"gr", + "it":[ { - "ind": 0, - "ty": "sh", - "ix": 1, - "ks": { - "a": 0, - "k": { - "i": [ + "ind":0, + "ty":"sh", + "ix":1, + "ks":{ + "a":0, + "k":{ + "i":[ [ 0, 0 ], [ - 3.2, + 1.307, + -0.561 + ], + [ + 0.894, + -0.16 + ], + [ + 0.706, 0 ], [ - 2.217, - 2.066 + 0.844, + 0.193 + ], + [ + 0.728, + 0.334 + ], + [ + 0.967, + 0.901 ] ], - "o": [ + "o":[ [ - -2.217, - 2.066 + -1.038, + 0.967 ], [ - -3.2, + -0.817, + 0.351 + ], + [ + -0.673, + 0.12 + ], + [ + -0.9, 0 ], [ + -0.794, + -0.182 + ], + [ + -1.203, + -0.551 + ], + [ 0, 0 ] ], - "v": [ + "v":[ [ - 8.75, - -1.667 + 8.182, + -1.636 ], [ - 0, - 1.667 + 4.642, + 0.681 + ], + [ + 2.07, + 1.453 + ], + [ + -0.001, + 1.636 + ], + [ + -2.621, + 1.341 + ], + [ + -4.909, + 0.563 ], [ - -8.75, - -1.667 + -8.182, + -1.636 ] ], - "c": false + "c":false }, - "ix": 2 + "ix":2 }, - "nm": "Path 1", - "mn": "ADBE Vector Shape - Group", - "hd": false + "nm":"Path 1", + "mn":"ADBE Vector Shape - Group", + "hd":false }, { - "ty": "tm", - "s": { - "a": 0, - "k": 0, - "ix": 1 - }, - "e": { - "a": 0, - "k": 69, - "ix": 2 - }, - "o": { - "a": 1, - "k": [ - { - "i": { - "x": [ - 0.833 - ], - "y": [ - 0.833 - ] - }, - "o": { - "x": [ - 0.167 - ], - "y": [ - 0.167 - ] - }, - "t": 0, - "s": [ - 0 - ] - }, - { - "t": 360, - "s": [ - 720 - ] - } - ], - "ix": 3 - }, - "m": 1, - "ix": 2, - "nm": "Trim Paths 1", - "mn": "ADBE Vector Filter - Trim", - "hd": false - }, - { - "ty": "st", - "c": { - "a": 0, - "k": [ + "ty":"st", + "c":{ + "a":0, + "k":[ 1, 1, 1, 1 ], - "ix": 3 - }, - "o": { - "a": 0, - "k": 100, - "ix": 4 - }, - "w": { - "a": 0, - "k": 1, - "ix": 5 - }, - "lc": 2, - "lj": 1, - "ml": 10, - "bm": 0, - "d": [ - { - "n": "d", - "nm": "dash", - "v": { - "a": 0, - "k": 0, - "ix": 1 - } - }, - { - "n": "o", - "nm": "offset", - "v": { - "a": 0, - "k": 25, - "ix": 7 - } - } - ], - "nm": "Stroke 1", - "mn": "ADBE Vector Graphic - Stroke", - "hd": false + "ix":3 + }, + "o":{ + "a":0, + "k":100, + "ix":4 + }, + "w":{ + "a":0, + "k":1, + "ix":5 + }, + "lc":2, + "lj":1, + "ml":10, + "bm":0, + "nm":"Stroke 1", + "mn":"ADBE Vector Graphic - Stroke", + "hd":false }, { - "ty": "tr", - "p": { - "a": 0, - "k": [ - 20, - 42.083 + "ty":"tr", + "p":{ + "a":0, + "k":[ + 19.341, + 40.614 ], - "ix": 2 + "ix":2 }, - "a": { - "a": 0, - "k": [ + "a":{ + "a":0, + "k":[ 0, 0 ], - "ix": 1 + "ix":1 }, - "s": { - "a": 0, - "k": [ + "s":{ + "a":0, + "k":[ 100, 100 ], - "ix": 3 + "ix":3 }, - "r": { - "a": 0, - "k": 0, - "ix": 6 + "r":{ + "a":0, + "k":0, + "ix":6 }, - "o": { - "a": 0, - "k": 100, - "ix": 7 + "o":{ + "a":0, + "k":100, + "ix":7 }, - "sk": { - "a": 0, - "k": 0, - "ix": 4 + "sk":{ + "a":0, + "k":0, + "ix":4 }, - "sa": { - "a": 0, - "k": 0, - "ix": 5 + "sa":{ + "a":0, + "k":0, + "ix":5 }, - "nm": "Transform" + "nm":"Transform" } ], - "nm": "Group 1", - "np": 3, - "cix": 2, - "bm": 0, - "ix": 1, - "mn": "ADBE Vector Group", - "hd": false + "nm":"Bottom", + "np":2, + "cix":2, + "bm":0, + "ix":1, + "mn":"ADBE Vector Group", + "hd":false + }, + { + "ty":"tm", + "s":{ + "a":0, + "k":0, + "ix":1 + }, + "e":{ + "a":0, + "k":69, + "ix":2 + }, + "o":{ + "a":1, + "k":[ + { + "i":{ + "x":[ + 0.833 + ], + "y":[ + 0.833 + ] + }, + "o":{ + "x":[ + 0.167 + ], + "y":[ + 0.167 + ] + }, + "t":0, + "s":[ + 0 + ] + }, + { + "t":360, + "s":[ + 720 + ] + } + ], + "ix":3 + }, + "m":1, + "ix":2, + "nm":"Trim Paths 1", + "mn":"ADBE Vector Filter - Trim", + "hd":false } ], - "ip": 0, - "op": 600, - "st": 0, - "bm": 0 + "ip":0, + "op":600, + "st":0, + "bm":0 } ], - "markers": [ + "markers":[ { - "tm": 210, - "cm": "2", - "dr": 0 + "tm":210, + "cm":"2", + "dr":0 }, { - "tm": 255, - "cm": "1", - "dr": 0 + "tm":255, + "cm":"1", + "dr":0 } ] }
\ No newline at end of file diff --git a/packages/SystemUI/res/raw/udfps_lockscreen_fp.json b/packages/SystemUI/res/raw/udfps_lockscreen_fp.json index cef433ef95d2..a25a47595fe7 100644 --- a/packages/SystemUI/res/raw/udfps_lockscreen_fp.json +++ b/packages/SystemUI/res/raw/udfps_lockscreen_fp.json @@ -1,1017 +1 @@ -{ - "v": "5.7.8", - "fr": 60, - "ip": 0, - "op": 46, - "w": 180, - "h": 185, - "nm": "fingerprint_build_on", - "ddd": 0, - "assets": [], - "layers": [ - { - "ddd": 0, - "ind": 1, - "ty": 4, - "nm": "fingerprint_build_on", - "sr": 1, - "ks": { - "o": { - "a": 0, - "k": 100, - "ix": 11 - }, - "r": { - "a": 0, - "k": 0, - "ix": 10 - }, - "p": { - "a": 0, - "k": [ - 91.456, - 92.206, - 0 - ], - "ix": 2, - "l": 2 - }, - "a": { - "a": 0, - "k": [ - 20, - 25, - 0 - ], - "ix": 1, - "l": 2 - }, - "s": { - "a": 0, - "k": [ - 350, - 350, - 100 - ], - "ix": 6, - "l": 2 - } - }, - "ao": 0, - "shapes": [ - { - "ty": "gr", - "it": [ - { - "ind": 0, - "ty": "sh", - "ix": 1, - "ks": { - "a": 0, - "k": { - "i": [ - [ - 0, - 0 - ], - [ - 3.2, - 0 - ], - [ - 2.217, - 2.066 - ] - ], - "o": [ - [ - -2.217, - 2.066 - ], - [ - -3.2, - 0 - ], - [ - 0, - 0 - ] - ], - "v": [ - [ - 8.75, - -1.667 - ], - [ - 0, - 1.667 - ], - [ - -8.75, - -1.667 - ] - ], - "c": false - }, - "ix": 2 - }, - "nm": "Path 1", - "mn": "ADBE Vector Shape - Group", - "hd": false - }, - { - "ty": "tm", - "s": { - "a": 0, - "k": 0, - "ix": 1 - }, - "e": { - "a": 0, - "k": 100, - "ix": 2 - }, - "o": { - "a": 0, - "k": 0, - "ix": 3 - }, - "m": 1, - "ix": 2, - "nm": "Trim Paths 1", - "mn": "ADBE Vector Filter - Trim", - "hd": false - }, - { - "ty": "st", - "c": { - "a": 0, - "k": [ - 1, - 1, - 1, - 1 - ], - "ix": 3 - }, - "o": { - "a": 0, - "k": 100, - "ix": 4 - }, - "w": { - "a": 1, - "k": [ - { - "i": { - "x": [ - 0 - ], - "y": [ - 1 - ] - }, - "o": { - "x": [ - 0.167 - ], - "y": [ - 0.167 - ] - }, - "t": 0, - "s": [ - 0 - ] - }, - { - "t": 24, - "s": [ - 2.5 - ] - } - ], - "ix": 5 - }, - "lc": 2, - "lj": 1, - "ml": 10, - "bm": 0, - "d": [ - { - "n": "d", - "nm": "dash", - "v": { - "a": 0, - "k": 0, - "ix": 1 - } - }, - { - "n": "o", - "nm": "offset", - "v": { - "a": 0, - "k": 0, - "ix": 7 - } - } - ], - "nm": "Stroke 1", - "mn": "ADBE Vector Graphic - Stroke", - "hd": false - }, - { - "ty": "tr", - "p": { - "a": 0, - "k": [ - 20, - 42.083 - ], - "ix": 2 - }, - "a": { - "a": 0, - "k": [ - 0, - 0 - ], - "ix": 1 - }, - "s": { - "a": 0, - "k": [ - 100, - 100 - ], - "ix": 3 - }, - "r": { - "a": 0, - "k": 0, - "ix": 6 - }, - "o": { - "a": 0, - "k": 100, - "ix": 7 - }, - "sk": { - "a": 0, - "k": 0, - "ix": 4 - }, - "sa": { - "a": 0, - "k": 0, - "ix": 5 - }, - "nm": "Transform" - } - ], - "nm": "Group 1", - "np": 3, - "cix": 2, - "bm": 0, - "ix": 1, - "mn": "ADBE Vector Group", - "hd": false - }, - { - "ty": "gr", - "it": [ - { - "ind": 0, - "ty": "sh", - "ix": 1, - "ks": { - "a": 0, - "k": { - "i": [ - [ - 0, - 0 - ], - [ - -5.883, - 0 - ], - [ - -2.367, - -3.933 - ] - ], - "o": [ - [ - 2.367, - -3.933 - ], - [ - 5.883, - 0 - ], - [ - 0, - 0 - ] - ], - "v": [ - [ - -13.75, - 3.333 - ], - [ - 0, - -3.333 - ], - [ - 13.75, - 3.333 - ] - ], - "c": false - }, - "ix": 2 - }, - "nm": "Path 1", - "mn": "ADBE Vector Shape - Group", - "hd": false - }, - { - "ty": "tm", - "s": { - "a": 0, - "k": 0, - "ix": 1 - }, - "e": { - "a": 0, - "k": 100, - "ix": 2 - }, - "o": { - "a": 0, - "k": 0, - "ix": 3 - }, - "m": 1, - "ix": 2, - "nm": "Trim Paths 1", - "mn": "ADBE Vector Filter - Trim", - "hd": false - }, - { - "ty": "st", - "c": { - "a": 0, - "k": [ - 1, - 1, - 1, - 1 - ], - "ix": 3 - }, - "o": { - "a": 0, - "k": 100, - "ix": 4 - }, - "w": { - "a": 1, - "k": [ - { - "i": { - "x": [ - 0 - ], - "y": [ - 1 - ] - }, - "o": { - "x": [ - 0.167 - ], - "y": [ - 0.167 - ] - }, - "t": 0, - "s": [ - 0 - ] - }, - { - "t": 24, - "s": [ - 2.5 - ] - } - ], - "ix": 5 - }, - "lc": 2, - "lj": 1, - "ml": 10, - "bm": 0, - "nm": "Stroke 1", - "mn": "ADBE Vector Graphic - Stroke", - "hd": false - }, - { - "ty": "tr", - "p": { - "a": 0, - "k": [ - 20, - 16.25 - ], - "ix": 2 - }, - "a": { - "a": 0, - "k": [ - 0, - 0 - ], - "ix": 1 - }, - "s": { - "a": 0, - "k": [ - 100, - 100 - ], - "ix": 3 - }, - "r": { - "a": 0, - "k": 0, - "ix": 6 - }, - "o": { - "a": 0, - "k": 100, - "ix": 7 - }, - "sk": { - "a": 0, - "k": 0, - "ix": 4 - }, - "sa": { - "a": 0, - "k": 0, - "ix": 5 - }, - "nm": "Transform" - } - ], - "nm": "Group 2", - "np": 3, - "cix": 2, - "bm": 0, - "ix": 2, - "mn": "ADBE Vector Group", - "hd": false - }, - { - "ty": "gr", - "it": [ - { - "ind": 0, - "ty": "sh", - "ix": 1, - "ks": { - "a": 0, - "k": { - "i": [ - [ - 0, - 0 - ], - [ - -3.684, - 0 - ], - [ - -2.883, - -1.583 - ] - ], - "o": [ - [ - 2.883, - -1.583 - ], - [ - 3.683, - 0 - ], - [ - 0, - 0 - ] - ], - "v": [ - [ - -10.417, - 1.25 - ], - [ - 0.001, - -1.25 - ], - [ - 10.417, - 1.25 - ] - ], - "c": false - }, - "ix": 2 - }, - "nm": "Path 1", - "mn": "ADBE Vector Shape - Group", - "hd": false - }, - { - "ty": "tm", - "s": { - "a": 0, - "k": 0, - "ix": 1 - }, - "e": { - "a": 0, - "k": 100, - "ix": 2 - }, - "o": { - "a": 0, - "k": 0, - "ix": 3 - }, - "m": 1, - "ix": 2, - "nm": "Trim Paths 1", - "mn": "ADBE Vector Filter - Trim", - "hd": false - }, - { - "ty": "st", - "c": { - "a": 0, - "k": [ - 1, - 1, - 1, - 1 - ], - "ix": 3 - }, - "o": { - "a": 0, - "k": 100, - "ix": 4 - }, - "w": { - "a": 1, - "k": [ - { - "i": { - "x": [ - 0 - ], - "y": [ - 1 - ] - }, - "o": { - "x": [ - 0.167 - ], - "y": [ - 0.167 - ] - }, - "t": 0, - "s": [ - 0 - ] - }, - { - "t": 24, - "s": [ - 2.5 - ] - } - ], - "ix": 5 - }, - "lc": 2, - "lj": 1, - "ml": 10, - "bm": 0, - "nm": "Stroke 1", - "mn": "ADBE Vector Graphic - Stroke", - "hd": false - }, - { - "ty": "tr", - "p": { - "a": 0, - "k": [ - 19.999, - 7.5 - ], - "ix": 2 - }, - "a": { - "a": 0, - "k": [ - 0, - 0 - ], - "ix": 1 - }, - "s": { - "a": 0, - "k": [ - 100, - 100 - ], - "ix": 3 - }, - "r": { - "a": 0, - "k": 0, - "ix": 6 - }, - "o": { - "a": 0, - "k": 100, - "ix": 7 - }, - "sk": { - "a": 0, - "k": 0, - "ix": 4 - }, - "sa": { - "a": 0, - "k": 0, - "ix": 5 - }, - "nm": "Transform" - } - ], - "nm": "Group 3", - "np": 3, - "cix": 2, - "bm": 0, - "ix": 3, - "mn": "ADBE Vector Group", - "hd": false - }, - { - "ty": "gr", - "it": [ - { - "ind": 0, - "ty": "sh", - "ix": 1, - "ks": { - "a": 0, - "k": { - "i": [ - [ - 0, - 0 - ], - [ - 0, - 0 - ], - [ - -6.65, - 0 - ], - [ - 0, - -5.9 - ], - [ - 0, - 0 - ], - [ - 2.333, - 0 - ], - [ - 0.633, - 1.601 - ], - [ - 0, - 0 - ], - [ - 1.717, - 0 - ], - [ - 0, - 0 - ], - [ - 0, - -2.2 - ], - [ - -2.15, - -1.716 - ], - [ - 0, - 0 - ] - ], - "o": [ - [ - -0.767, - -2.134 - ], - [ - 0, - -5.917 - ], - [ - 6.65, - 0 - ], - [ - 0, - 0 - ], - [ - 0, - 2.333 - ], - [ - -1.734, - 0 - ], - [ - 0, - 0 - ], - [ - -0.634, - -1.599 - ], - [ - 0, - 0 - ], - [ - -2.2, - 0 - ], - [ - 0, - 2.75 - ], - [ - 0, - 0 - ], - [ - 0, - 0 - ] - ], - "v": [ - [ - -11.108, - 5.825 - ], - [ - -11.875, - 1.525 - ], - [ - -0.208, - -9.175 - ], - [ - 11.875, - 1.525 - ], - [ - 11.875, - 1.592 - ], - [ - 7.659, - 5.808 - ], - [ - 3.742, - 3.158 - ], - [ - 2.526, - 0.141 - ], - [ - -1.391, - -2.508 - ], - [ - -1.641, - -2.508 - ], - [ - -5.625, - 1.475 - ], - [ - -2.225, - 8.558 - ], - [ - -1.458, - 9.175 - ] - ], - "c": false - }, - "ix": 2 - }, - "nm": "Path 1", - "mn": "ADBE Vector Shape - Group", - "hd": false - }, - { - "ty": "tm", - "s": { - "a": 0, - "k": 0, - "ix": 1 - }, - "e": { - "a": 0, - "k": 100, - "ix": 2 - }, - "o": { - "a": 0, - "k": 0, - "ix": 3 - }, - "m": 1, - "ix": 2, - "nm": "Trim Paths 1", - "mn": "ADBE Vector Filter - Trim", - "hd": false - }, - { - "ty": "st", - "c": { - "a": 0, - "k": [ - 1, - 1, - 1, - 1 - ], - "ix": 3 - }, - "o": { - "a": 0, - "k": 100, - "ix": 4 - }, - "w": { - "a": 1, - "k": [ - { - "i": { - "x": [ - 0 - ], - "y": [ - 1 - ] - }, - "o": { - "x": [ - 0.167 - ], - "y": [ - 0.167 - ] - }, - "t": 0, - "s": [ - 0 - ] - }, - { - "t": 24, - "s": [ - 2.5 - ] - } - ], - "ix": 5 - }, - "lc": 2, - "lj": 1, - "ml": 10, - "bm": 0, - "nm": "Stroke 1", - "mn": "ADBE Vector Graphic - Stroke", - "hd": false - }, - { - "ty": "tr", - "p": { - "a": 0, - "k": [ - 19.992, - 28.758 - ], - "ix": 2 - }, - "a": { - "a": 0, - "k": [ - 0, - 0 - ], - "ix": 1 - }, - "s": { - "a": 0, - "k": [ - 100, - 100 - ], - "ix": 3 - }, - "r": { - "a": 0, - "k": 0, - "ix": 6 - }, - "o": { - "a": 0, - "k": 100, - "ix": 7 - }, - "sk": { - "a": 0, - "k": 0, - "ix": 4 - }, - "sa": { - "a": 0, - "k": 0, - "ix": 5 - }, - "nm": "Transform" - } - ], - "nm": "Group 4", - "np": 3, - "cix": 2, - "bm": 0, - "ix": 4, - "mn": "ADBE Vector Group", - "hd": false - } - ], - "ip": 0, - "op": 600, - "st": 0, - "bm": 0 - } - ], - "markers": [ - { - "tm": 210, - "cm": "2", - "dr": 0 - }, - { - "tm": 255, - "cm": "1", - "dr": 0 - } - ] -}
\ No newline at end of file +{"v":"5.7.8","fr":60,"ip":0,"op":46,"w":46,"h":65,"nm":"fingerprint_build_on","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Fingerprint_20210701 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[23.091,32.5,0],"ix":2,"l":2},"a":{"a":0,"k":[19.341,24.25,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-1.701,0.42],[-1.757,0],[-1.577,-0.381],[-1.485,-0.816]],"o":[[1.455,-0.799],[1.608,-0.397],[1.719,0],[1.739,0.42],[0,0]],"v":[[-9.818,1.227],[-5.064,-0.618],[0,-1.227],[4.96,-0.643],[9.818,1.227]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999985639,0.948999980852,0.62400004069,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":24,"s":[2.5]}],"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[19.341,7.477],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Top","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-2.446,1.161],[-1.168,0.275],[-1.439,0],[-1.301,-0.304],[-1.225,-0.66],[-1.11,-1.844]],"o":[[1.23,-2.044],[1.024,-0.486],[1.312,-0.31],[1.425,0],[1.454,0.34],[2.122,1.143],[0,0]],"v":[[-13.091,3.273],[-7.438,-1.646],[-4.14,-2.797],[0,-3.273],[4.104,-2.805],[8.141,-1.29],[13.091,3.273]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999985639,0.948999980852,0.62400004069,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":24,"s":[2.5]}],"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[19.341,16.069],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Mid Top","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-6.53,0],[0,-5.793],[0,0],[2.159,0],[0.59,1.489],[0,0],[1.587,0],[0,-2.16],[-0.81,-1.363],[-0.844,-0.674],[0,0]],"o":[[-0.753,-2.095],[0,-5.793],[6.529,0],[0,0],[0,2.16],[-1.604,0],[0,0],[-0.589,-1.489],[-2.161,0],[0,1.62],[0.54,0.909],[0,0],[0,0]],"v":[[-10.702,5.728],[-11.454,1.506],[0.001,-9],[11.454,1.506],[11.454,1.817],[7.544,5.728],[3.926,3.273],[2.618,0],[-0.997,-2.454],[-4.91,1.457],[-3.657,6.014],[-1.57,8.412],[-0.818,9]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.949000000954,0.624000012875,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":24,"s":[2.5]}],"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[19.341,28.341],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Inside to dot ","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[1.307,-0.561],[0.894,-0.16],[0.706,0],[0.844,0.193],[0.728,0.334],[0.967,0.901]],"o":[[-1.038,0.967],[-0.817,0.351],[-0.673,0.12],[-0.9,0],[-0.794,-0.182],[-1.203,-0.551],[0,0]],"v":[[8.182,-1.636],[4.642,0.681],[2.07,1.453],[-0.001,1.636],[-2.621,1.341],[-4.909,0.563],[-8.182,-1.636]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999985639,0.948999980852,0.62400004069,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":24,"s":[2.5]}],"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[19.341,40.614],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Bottom","np":2,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}],"markers":[{"tm":210,"cm":"2","dr":0},{"tm":255,"cm":"1","dr":0}]}
\ No newline at end of file diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml index 7fc978bfb0a4..9598e87a2f40 100644 --- a/packages/SystemUI/res/values-af/strings.xml +++ b/packages/SystemUI/res/values-af/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Beweeg na rand en versteek"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Beweeg weg van rand en wys"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"wissel"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"Huiskontroles"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Toestelkontroles"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Kies program om kontroles by te voeg"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> kontroles bygevoeg.</item> @@ -1149,6 +1149,7 @@ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> het \'n boodskap gestuur: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> het \'n prent gestuur"</string> <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> het \'n statusopdatering: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <string name="person_available" msgid="2318599327472755472">"Beskikbaar"</string> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Kon nie jou batterymeter lees nie"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Tik vir meer inligting"</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Geen wekker nie"</string> diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml index 6b9e40d3cffa..d9a3da392fc5 100644 --- a/packages/SystemUI/res/values-am/strings.xml +++ b/packages/SystemUI/res/values-am/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"ወደ ጠርዝ አንቀሳቅስ እና ደደብቅ"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"ጠርዙን ወደ ውጭ አንቀሳቅስ እና አሳይ"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"ቀያይር"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"የቤት ውስጥ ቁጥጥሮች"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"የመሣሪያ መቆጣጠሪያዎች"</string> <string name="controls_providers_title" msgid="6879775889857085056">"መቆጣጠሪያዎችን ለማከል መተግበሪያ ይምረጡ"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> ቁጥጥሮች ታክለዋል።</item> @@ -1149,6 +1149,8 @@ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> መልዕክት ልከዋል፦ <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ምስል ልኳል"</string> <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> የሁኔታ ዝማኔ አለው፦ <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <!-- no translation found for person_available (2318599327472755472) --> + <skip /> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"የባትሪ መለኪያዎን የማንበብ ችግር"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"ለበለጠ መረጃ መታ ያድርጉ"</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"ምንም ማንቂያ አልተቀናበረም"</string> diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml index fe91b68036da..bfcfd9bd41d5 100644 --- a/packages/SystemUI/res/values-ar/strings.xml +++ b/packages/SystemUI/res/values-ar/strings.xml @@ -1064,7 +1064,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"نقله إلى الحافة وإخفاؤه"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"نقله إلى خارج الحافة وإظهاره"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"إيقاف/تفعيل"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"إدارة آلية للمنزل"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"أدوات التحكم بالأجهزة"</string> <string name="controls_providers_title" msgid="6879775889857085056">"اختيار تطبيق لإضافة عناصر التحكّم"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="zero">تمت إضافة <xliff:g id="NUMBER_1">%s</xliff:g> عنصر تحكّم.</item> @@ -1170,10 +1170,10 @@ <string name="people_tile_description" msgid="8154966188085545556">"عرض أحدث الرسائل والمكالمات الفائتة والتغييرات في الحالة"</string> <string name="people_tile_title" msgid="6589377493334871272">"محادثة"</string> <string name="paused_by_dnd" msgid="7856941866433556428">"تم إيقاف الإشعار مؤقتًا من خلال ميزة \"عدم الإزعاج\""</string> - <!-- no translation found for new_notification_text_content_description (2915029960094389291) --> - <skip /> + <string name="new_notification_text_content_description" msgid="2915029960094389291">"تم إرسال رسالة من <xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"تم إرسال صورة من <xliff:g id="NAME">%1$s</xliff:g>."</string> - <!-- no translation found for new_status_content_description (6046637888641308327) --> + <string name="new_status_content_description" msgid="6046637888641308327">"تم تعديل حالة <xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <!-- no translation found for person_available (2318599327472755472) --> <skip /> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"حدثت مشكلة أثناء قراءة مقياس مستوى شحن البطارية."</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"انقر للحصول على مزيد من المعلومات."</string> diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml index ba6d3f473105..316c87b18df0 100644 --- a/packages/SystemUI/res/values-as/strings.xml +++ b/packages/SystemUI/res/values-as/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"কাষলৈ নিয়ক আৰু লুকুৱাওক"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"কাষৰ বাহিৰলৈ নিয়ক আৰু দেখুৱাওক"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"ট’গল কৰক"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"গৃহ নিয়ন্ত্ৰণ"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"ডিভাইচৰ নিয়ন্ত্ৰণসমূহ"</string> <string name="controls_providers_title" msgid="6879775889857085056">"নিয়ন্ত্ৰণসমূহ যোগ কৰিবলৈ এপ্ বাছনি কৰক"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> টা নিয়ন্ত্ৰণ যোগ কৰা হ’ল।</item> @@ -1146,10 +1146,10 @@ <string name="people_tile_description" msgid="8154966188085545556">"শেহতীয়া বাৰ্তা, মিছড্ কল আৰু স্থিতিৰ আপডে’ট চাওক"</string> <string name="people_tile_title" msgid="6589377493334871272">"বাৰ্তালাপ"</string> <string name="paused_by_dnd" msgid="7856941866433556428">"অসুবিধা নিদিব সুবিধাটোৱে পজ কৰিছে"</string> - <!-- no translation found for new_notification_text_content_description (2915029960094389291) --> - <skip /> + <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g>এ এটা বাৰ্তা পঠিয়াইছে: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g>এ এখন প্ৰতিচ্ছবি পঠিয়াইছে"</string> - <!-- no translation found for new_status_content_description (6046637888641308327) --> + <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g>ৰ এটা স্থিতিৰ আপডে’ট আছে: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <!-- no translation found for person_available (2318599327472755472) --> <skip /> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"আপোনাৰ বেটাৰী মিটাৰ পঢ়োঁতে সমস্যা হৈছে"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"অধিক তথ্যৰ বাবে টিপক"</string> diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml index 5cb4422e6603..ede3b1697fd7 100644 --- a/packages/SystemUI/res/values-az/strings.xml +++ b/packages/SystemUI/res/values-az/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"İçəri keçirib gizlədin"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Kənara daşıyıb göstərin"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"keçirin"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"Əsas səhifə nizamlayıcıları"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Cihaz kontrolları"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Kontrol əlavə etmək üçün tətbiq seçin"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> nizamlayıcı əlavə edilib.</item> @@ -1146,10 +1146,10 @@ <string name="people_tile_description" msgid="8154966188085545556">"Son mesajlar, buraxılmış zənglər və status güncəlləmələrinə baxın"</string> <string name="people_tile_title" msgid="6589377493334871272">"Söhbət"</string> <string name="paused_by_dnd" msgid="7856941866433556428">"\"Narahat Etməyin\" rejimini tərəfindən durdurulub"</string> - <!-- no translation found for new_notification_text_content_description (2915029960094389291) --> - <skip /> + <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> mesaj göndərdi: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> şəkil göndərdi"</string> - <!-- no translation found for new_status_content_description (6046637888641308327) --> + <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> status güncəlləməsi edib: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <!-- no translation found for person_available (2318599327472755472) --> <skip /> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Batareya ölçüsünü oxuyarkən problem yarandı"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Ətraflı məlumat üçün toxunun"</string> diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml index a179b93ad4cf..d48eebcd1cde 100644 --- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml +++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml @@ -1049,7 +1049,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Premesti do ivice i sakrij"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Premesti izvan ivice i prikaži"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"uključite/isključite"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"Kontrole za dom"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Kontrole uređaja"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Odaberite aplikaciju za dodavanje kontrola"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> kontrola je dodata.</item> @@ -1155,6 +1155,7 @@ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> je poslao/la poruku: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> šalje sliku"</string> <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> ima ažuriranje statusa: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <string name="person_available" msgid="2318599327472755472">"Dostupno"</string> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problem sa očitavanjem merača baterije"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Dodirnite za više informacija"</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Alarm nije podešen"</string> diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml index 704c19c6e8b4..8cbc8bd31e41 100644 --- a/packages/SystemUI/res/values-be/strings.xml +++ b/packages/SystemUI/res/values-be/strings.xml @@ -1054,7 +1054,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Перамясціць на край і схаваць"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Перамясціць за край і паказаць"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"уключыць/выключыць"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"Элементы кіравання домам"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Элементы кіравання прыладай"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Выберыце праграму для дадавання элементаў кіравання"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="one">Дададзены <xliff:g id="NUMBER_1">%s</xliff:g> элемент кіравання.</item> @@ -1158,10 +1158,10 @@ <string name="people_tile_description" msgid="8154966188085545556">"Глядзець нядаўнія паведамленні, прапушчаныя выклікі і абнаўленні стану"</string> <string name="people_tile_title" msgid="6589377493334871272">"Размова"</string> <string name="paused_by_dnd" msgid="7856941866433556428">"Прыпынена функцыяй \"Не турбаваць\""</string> - <!-- no translation found for new_notification_text_content_description (2915029960094389291) --> - <skip /> + <string name="new_notification_text_content_description" msgid="2915029960094389291">"Карыстальнік <xliff:g id="NAME">%1$s</xliff:g> прыслаў паведамленне: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"Карыстальнік <xliff:g id="NAME">%1$s</xliff:g> адправіў відарыс"</string> - <!-- no translation found for new_status_content_description (6046637888641308327) --> + <string name="new_status_content_description" msgid="6046637888641308327">"Карыстальнік <xliff:g id="NAME">%1$s</xliff:g> абнавіў стан: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <!-- no translation found for person_available (2318599327472755472) --> <skip /> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Праблема з чытаннем індыкатара зараду акумулятара"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Націсніце, каб убачыць больш"</string> diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml index 2fc165eca9d5..da457436df64 100644 --- a/packages/SystemUI/res/values-bg/strings.xml +++ b/packages/SystemUI/res/values-bg/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Преместване в края и скриване"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Преместване в края и показване"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"превключване"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"Контроли за дома"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Контроли за устройството"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Изберете приложение, за да добавите контроли"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="other">Добавени са <xliff:g id="NUMBER_1">%s</xliff:g> контроли.</item> @@ -1146,11 +1146,10 @@ <string name="people_tile_description" msgid="8154966188085545556">"Преглеждайте скорошни съобщения, пропуснати обаждания и информация за състоянието"</string> <string name="people_tile_title" msgid="6589377493334871272">"Разговор"</string> <string name="paused_by_dnd" msgid="7856941866433556428">"Поставено на пауза от режима „Не безпокойте“"</string> - <!-- no translation found for new_notification_text_content_description (2915029960094389291) --> - <skip /> + <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> изпрати съобщение: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> изпрати изображение"</string> - <!-- no translation found for new_status_content_description (6046637888641308327) --> - <skip /> + <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> има актуализация на състоянието: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <string name="person_available" msgid="2318599327472755472">"Налице"</string> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Възникна проблем при четенето на данните за нивото на батерията"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Докоснете за още информация"</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Няма зададен будилник"</string> diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml index 04a734d0a4c6..2fe583a6abc7 100644 --- a/packages/SystemUI/res/values-bn/strings.xml +++ b/packages/SystemUI/res/values-bn/strings.xml @@ -669,9 +669,8 @@ <string name="wallet_empty_state_label" msgid="7776761245237530394">"ফোন ব্যবহার করে আরও দ্রুত ও আরও নিরাপদে কেনাকাটা করার জন্য সেট-আপ করুন"</string> <string name="wallet_app_button_label" msgid="7123784239111190992">"সবকটি দেখুন"</string> <string name="wallet_action_button_label_unlock" msgid="8663239748726774487">"পেমেন্ট করতে ডিভাইস আনলক করুন"</string> - <!-- no translation found for wallet_secondary_label_no_card (530725155985223497) --> - <skip /> - <string name="wallet_secondary_label_updating" msgid="5726130686114928551">"আপডেট হচ্ছে"</string> + <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"কার্ড যোগ করুন"</string> + <string name="wallet_secondary_label_updating" msgid="5726130686114928551">"আপডেট করা হচ্ছে"</string> <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ব্যবহার করতে আনলক করুন"</string> <string name="wallet_error_generic" msgid="257704570182963611">"আপনার কার্ড সংক্রান্ত তথ্য পেতে সমস্যা হয়েছে, পরে আবার চেষ্টা করুন"</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"লক স্ক্রিন সেটিংস"</string> @@ -1045,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"প্রান্তে যান ও আড়াল করুন"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"প্রান্ত থেকে সরান এবং দেখুন"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"টগল করুন"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"হোম কন্ট্রোল"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"ডিভাইস কন্ট্রোল"</string> <string name="controls_providers_title" msgid="6879775889857085056">"কন্ট্রোল যোগ করতে অ্যাপ বেছে নিন"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g>টি কন্ট্রোল যোগ করা হয়েছে।</item> @@ -1147,10 +1146,10 @@ <string name="people_tile_description" msgid="8154966188085545556">"সাম্প্রতিক মেসেজ, মিসড কল এবং স্ট্যাটাস সংক্রান্ত আপডেট দেখুন"</string> <string name="people_tile_title" msgid="6589377493334871272">"কথোপকথন"</string> <string name="paused_by_dnd" msgid="7856941866433556428">"\'বিরক্ত করবে না\' মোডের মাধ্যমে পজ করা আছে"</string> - <!-- no translation found for new_notification_text_content_description (2915029960094389291) --> - <skip /> + <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> একটি মেসেজ পাঠিয়েছেন: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> একটি ছবি পাঠিয়েছেন"</string> - <!-- no translation found for new_status_content_description (6046637888641308327) --> + <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> একটি স্ট্যাটাস আপডেট করেছেন: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <!-- no translation found for person_available (2318599327472755472) --> <skip /> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"ব্যাটারির মিটারের রিডিং নেওয়ার সময় সমস্যা হয়েছে"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"আরও তথ্যের জন্য ট্যাপ করুন"</string> diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml index 47d07738c155..2dc7301d5e45 100644 --- a/packages/SystemUI/res/values-bs/strings.xml +++ b/packages/SystemUI/res/values-bs/strings.xml @@ -1049,7 +1049,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Pomjeranje do ivice i sakrivanje"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Pomjeranje izvan ivice i prikaz"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"aktiviranje/deaktiviranje"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"Kontrole doma"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Kontrole uređaja"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Odaberite aplikaciju da dodate kontrole"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="one">Dodana je <xliff:g id="NUMBER_1">%s</xliff:g> kontrola.</item> @@ -1155,6 +1155,7 @@ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> je poslao/la poruku: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> je poslao/la sliku"</string> <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> je ažurirao/la status: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <string name="person_available" msgid="2318599327472755472">"Dostupan/na je"</string> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Došlo je do problema prilikom očitavanja mjerača stanja baterije"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Dodirnite za više informacija"</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Nije postavljen alarm"</string> diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml index abcefec326ff..abd4fddaee25 100644 --- a/packages/SystemUI/res/values-ca/strings.xml +++ b/packages/SystemUI/res/values-ca/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Mou dins de les vores i amaga"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Mou fora de les vores i mostra"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"commuta"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"Domòtica"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Controls de dispositius"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Selecciona l\'aplicació per afegir controls"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="other">S\'han afegit <xliff:g id="NUMBER_1">%s</xliff:g> controls.</item> @@ -1149,6 +1149,8 @@ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> ha enviat un missatge: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ha enviat una imatge"</string> <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> té una actualització d\'estat: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <!-- no translation found for person_available (2318599327472755472) --> + <skip /> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Hi ha hagut un problema en llegir el mesurador de la bateria"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Toca per obtenir més informació"</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Cap alarma configurada"</string> diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml index bac30d8d7e05..25f796c0324f 100644 --- a/packages/SystemUI/res/values-cs/strings.xml +++ b/packages/SystemUI/res/values-cs/strings.xml @@ -1054,7 +1054,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Přesunout k okraji a skrýt"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Přesunout okraj ven a zobrazit"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"přepnout"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"Ovládání domácnosti"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Ovládání zařízení"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Vyberte aplikaci, pro kterou chcete přidat ovládací prvky"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="few">Byly přidány <xliff:g id="NUMBER_1">%s</xliff:g> ovládací prvky.</item> @@ -1158,11 +1158,10 @@ <string name="people_tile_description" msgid="8154966188085545556">"Zobrazit poslední zprávy, zmeškané hovory a aktualizace stavu"</string> <string name="people_tile_title" msgid="6589377493334871272">"Konverzace"</string> <string name="paused_by_dnd" msgid="7856941866433556428">"Pozastaveno funkcí Nerušit"</string> - <!-- no translation found for new_notification_text_content_description (2915029960094389291) --> - <skip /> + <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> posílá zprávu: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> posílá obrázek"</string> - <!-- no translation found for new_status_content_description (6046637888641308327) --> - <skip /> + <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> má aktualizaci stavu: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <string name="person_available" msgid="2318599327472755472">"Dostupné"</string> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problém s načtením měřiče baterie"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Klepnutím zobrazíte další informace"</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Budík nenastaven"</string> diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml index cb06aa76b184..06f6a35199e4 100644 --- a/packages/SystemUI/res/values-da/strings.xml +++ b/packages/SystemUI/res/values-da/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Flyt ud til kanten, og skjul"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Flyt ud til kanten, og vis"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"slå til/fra"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"Styring af smartenheder"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Enhedsstyring"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Vælg en app for at tilføje styring"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> styring er tilføjet.</item> @@ -1149,6 +1149,8 @@ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> har sendt en besked: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> har sendt et billede"</string> <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> har opdateret sin status: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <!-- no translation found for person_available (2318599327472755472) --> + <skip /> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Der er problemer med at aflæse dit batteriniveau"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Tryk for at få flere oplysninger"</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Ingen alarm er indstillet"</string> diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml index 36e837e02c9a..a92dd6fd9648 100644 --- a/packages/SystemUI/res/values-de/strings.xml +++ b/packages/SystemUI/res/values-de/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"An den Rand verschieben und verbergen"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Vom Rand verschieben und anzeigen"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"Wechseln"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"Smart-Home-Steuerung"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Gerätesteuerung"</string> <string name="controls_providers_title" msgid="6879775889857085056">"App zum Hinzufügen von Steuerelementen auswählen"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> Steuerelemente hinzugefügt.</item> @@ -1149,6 +1149,7 @@ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> hat eine Nachricht gesendet: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> hat ein Bild gesendet"</string> <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> hat den Status aktualisiert: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <string name="person_available" msgid="2318599327472755472">"Verfügbar"</string> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problem beim Lesen des Akkustands"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Für weitere Informationen tippen"</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Kein Wecker gestellt"</string> diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml index 04e69f10c83f..0e602645c1f7 100644 --- a/packages/SystemUI/res/values-el/strings.xml +++ b/packages/SystemUI/res/values-el/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Μετακίν. στο άκρο και απόκρυψη"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Μετακ. εκτός άκρου και εμφάν."</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"εναλλαγή"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"Οικιακοί έλεγχοι"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Στοιχεία ελέγχου συσκευής"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Επιλογή εφαρμογής για προσθήκη στοιχείων ελέγχου"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="other">Προστέθηκαν <xliff:g id="NUMBER_1">%s</xliff:g> στοιχεία ελέγχου.</item> @@ -1149,6 +1149,8 @@ <string name="new_notification_text_content_description" msgid="2915029960094389291">"Ο χρήστης <xliff:g id="NAME">%1$s</xliff:g> έστειλε ένα μήνυμα: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"Ο χρήστης <xliff:g id="NAME">%1$s</xliff:g> έστειλε μια εικόνα"</string> <string name="new_status_content_description" msgid="6046637888641308327">"Ο χρήστης <xliff:g id="NAME">%1$s</xliff:g> έχει μια ενημέρωση κατάστασης: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <!-- no translation found for person_available (2318599327472755472) --> + <skip /> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Υπάρχει κάποιο πρόβλημα με την ανάγνωση του μετρητή μπαταρίας"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Πατήστε για περισσότερες πληροφορίες."</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Δεν ορίστηκε ξυπνητ."</string> diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml index 043c374496c5..fd540633bb0b 100644 --- a/packages/SystemUI/res/values-en-rAU/strings.xml +++ b/packages/SystemUI/res/values-en-rAU/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Move to edge and hide"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Move out edge and show"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"toggle"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"Home controls"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Device controls"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Choose app to add controls"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> controls added.</item> @@ -1149,6 +1149,7 @@ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> sent a message: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> sent an image"</string> <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> has a status update: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <string name="person_available" msgid="2318599327472755472">"Available"</string> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problem reading your battery meter"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Tap for more information"</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"No alarm set"</string> diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml index 514747ada968..dff3c3035a43 100644 --- a/packages/SystemUI/res/values-en-rCA/strings.xml +++ b/packages/SystemUI/res/values-en-rCA/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Move to edge and hide"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Move out edge and show"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"toggle"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"Home controls"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Device controls"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Choose app to add controls"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> controls added.</item> @@ -1149,6 +1149,7 @@ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> sent a message: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> sent an image"</string> <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> has a status update: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <string name="person_available" msgid="2318599327472755472">"Available"</string> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problem reading your battery meter"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Tap for more information"</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"No alarm set"</string> diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml index 043c374496c5..fd540633bb0b 100644 --- a/packages/SystemUI/res/values-en-rGB/strings.xml +++ b/packages/SystemUI/res/values-en-rGB/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Move to edge and hide"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Move out edge and show"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"toggle"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"Home controls"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Device controls"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Choose app to add controls"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> controls added.</item> @@ -1149,6 +1149,7 @@ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> sent a message: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> sent an image"</string> <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> has a status update: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <string name="person_available" msgid="2318599327472755472">"Available"</string> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problem reading your battery meter"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Tap for more information"</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"No alarm set"</string> diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml index 043c374496c5..fd540633bb0b 100644 --- a/packages/SystemUI/res/values-en-rIN/strings.xml +++ b/packages/SystemUI/res/values-en-rIN/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Move to edge and hide"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Move out edge and show"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"toggle"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"Home controls"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Device controls"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Choose app to add controls"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> controls added.</item> @@ -1149,6 +1149,7 @@ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> sent a message: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> sent an image"</string> <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> has a status update: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <string name="person_available" msgid="2318599327472755472">"Available"</string> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problem reading your battery meter"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Tap for more information"</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"No alarm set"</string> diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml index 2c739667d252..97976dbdc1c0 100644 --- a/packages/SystemUI/res/values-en-rXC/strings.xml +++ b/packages/SystemUI/res/values-en-rXC/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Move to edge and hide"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Move out edge and show"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"toggle"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"Home controls"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Device controls"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Choose app to add controls"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> controls added.</item> @@ -1149,6 +1149,7 @@ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> sent a message: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> sent an image"</string> <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> has a status update: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <string name="person_available" msgid="2318599327472755472">"Available"</string> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problem reading your battery meter"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Tap for more information"</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"No alarm set"</string> diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml index 0e1d014a9322..b5b82c8ed2b4 100644 --- a/packages/SystemUI/res/values-es-rUS/strings.xml +++ b/packages/SystemUI/res/values-es-rUS/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Mover fuera de borde y ocultar"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Mover fuera de borde y mostrar"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"activar o desactivar"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"Controles de la casa"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Controles de dispositivos"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Elige la app para agregar los controles"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="other">Se agregaron <xliff:g id="NUMBER_1">%s</xliff:g> controles.</item> @@ -1149,6 +1149,8 @@ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> envió un mensaje: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> envió una imagen"</string> <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> actualizó su estado: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <!-- no translation found for person_available (2318599327472755472) --> + <skip /> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problema al leer el medidor de batería"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Presiona para obtener más información"</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"No se estableció alarma"</string> diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml index 6f23634469ef..9cdfe0a2cfdb 100644 --- a/packages/SystemUI/res/values-es/strings.xml +++ b/packages/SystemUI/res/values-es/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Mover al borde y ocultar"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Mover al borde y mostrar"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"activar/desactivar"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"Domótica"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Control de dispositivos"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Elige una aplicación para añadir controles"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="other">Se han añadido <xliff:g id="NUMBER_1">%s</xliff:g> controles.</item> @@ -1149,6 +1149,7 @@ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> ha enviado un mensaje: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ha enviado una imagen"</string> <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> ha cambiado su estado: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <string name="person_available" msgid="2318599327472755472">"Disponible"</string> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"No se ha podido leer el indicador de batería"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Toca la pantalla para consultar más información"</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Ninguna alarma puesta"</string> diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml index 682a24f5bcde..5e52394b02d8 100644 --- a/packages/SystemUI/res/values-et/strings.xml +++ b/packages/SystemUI/res/values-et/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Teisalda serva ja kuva"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Teisalda servast eemale ja kuva"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"lülita"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"Kodu juhtelemendid"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Seadmete juhikud"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Valige juhtelementide lisamiseks rakendus"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="other">Lisati <xliff:g id="NUMBER_1">%s</xliff:g> juhtnuppu.</item> @@ -1146,11 +1146,10 @@ <string name="people_tile_description" msgid="8154966188085545556">"Vaadake hiljutisi sõnumeid, vastamata kõnesid ja olekuvärskendusi"</string> <string name="people_tile_title" msgid="6589377493334871272">"Vestlus"</string> <string name="paused_by_dnd" msgid="7856941866433556428">"Peatas režiim Mitte segada"</string> - <!-- no translation found for new_notification_text_content_description (2915029960094389291) --> - <skip /> + <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> saatis sõnumi: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> saatis pildi"</string> - <!-- no translation found for new_status_content_description (6046637888641308327) --> - <skip /> + <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> värskendas olekut: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <string name="person_available" msgid="2318599327472755472">"Saadaval"</string> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Probleem akumõõdiku lugemisel"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Puudutage lisateabe saamiseks"</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Äratust pole"</string> diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml index 734fb3e57d9e..3e687d71b764 100644 --- a/packages/SystemUI/res/values-eu/strings.xml +++ b/packages/SystemUI/res/values-eu/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Eraman ertzera eta ezkutatu"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Atera ertzetik eta erakutsi"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"aldatu"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"Etxeko gailuak kontrolatzeko aukerak"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Gailuak kontrolatzeko widgetak"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Aukeratu aplikazio bat kontrolatzeko aukerak gehitzeko"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> kontrol-aukera gehitu dira.</item> @@ -1149,6 +1149,7 @@ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> erabiltzaileak mezu bat bidali du: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> erabiltzaileak irudi bat bidali du"</string> <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> erabiltzaileak egoera eguneratu du: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <string name="person_available" msgid="2318599327472755472">"Konektatuta"</string> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Arazo bat gertatu da bateria-neurgailua irakurtzean"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Informazio gehiago lortzeko, sakatu hau"</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Ez da ezarri alarmarik"</string> diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml index e85dba260723..b37a7be17247 100644 --- a/packages/SystemUI/res/values-fa/strings.xml +++ b/packages/SystemUI/res/values-fa/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"انتقال به لبه و پنهان کردن"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"انتقال به خارج از لبه و نمایش"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"روشن/ خاموش کردن"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"کنترلهای لوازم خانگی"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"کنترلهای دستگاه"</string> <string name="controls_providers_title" msgid="6879775889857085056">"انتخاب برنامه برای افزودن کنترلها"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> کنترل اضافه شده است.</item> @@ -1146,11 +1146,10 @@ <string name="people_tile_description" msgid="8154966188085545556">"دیدن بهروزرسانیهای وضعیت، تماسهای بیپاسخ، و پیامهای اخیر"</string> <string name="people_tile_title" msgid="6589377493334871272">"مکالمه"</string> <string name="paused_by_dnd" msgid="7856941866433556428">"با «مزاحم نشوید» موقتاً متوقف شده است"</string> - <!-- no translation found for new_notification_text_content_description (2915029960094389291) --> - <skip /> + <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> پیامی ارسال کرد: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> تصویری ارسال کرد"</string> - <!-- no translation found for new_status_content_description (6046637888641308327) --> - <skip /> + <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> وضعیتش را بهروزرسانی کرد: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <string name="person_available" msgid="2318599327472755472">"دردسترس"</string> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"مشکلی در خواندن میزان باتری وجود دارد"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"برای اطلاعات بیشتر ضربه بزنید"</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"هشداری تنظیم نشده است"</string> diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml index 98b9953ceee1..60bb0a1bd9e8 100644 --- a/packages/SystemUI/res/values-fi/strings.xml +++ b/packages/SystemUI/res/values-fi/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Siirrä reunaan ja piilota"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Siirrä pois reunasta ja näytä"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"vaihda"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"Kodin ohjaus"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Laitteiden hallinta"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Valitse sovellus lisätäksesi säätimiä"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> säädintä lisätty</item> @@ -1149,6 +1149,8 @@ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> lähetti viestin: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> lähetti kuvan"</string> <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> on päivittänyt tilansa: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <!-- no translation found for person_available (2318599327472755472) --> + <skip /> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Ongelma akkumittarin lukemisessa"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Saat lisätietoja napauttamalla"</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Ei herätyksiä"</string> diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml index 358d448a8500..74ff58e0649f 100644 --- a/packages/SystemUI/res/values-fr-rCA/strings.xml +++ b/packages/SystemUI/res/values-fr-rCA/strings.xml @@ -420,9 +420,9 @@ <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Jusqu\'à l\'aube"</string> <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Actif à <xliff:g id="TIME">%s</xliff:g>"</string> <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Jusqu\'à <xliff:g id="TIME">%s</xliff:g>"</string> - <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string> - <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC désactivée"</string> - <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC activée"</string> + <string name="quick_settings_nfc_label" msgid="1054317416221168085">"CCP"</string> + <string name="quick_settings_nfc_off" msgid="3465000058515424663">"CCP désactivée"</string> + <string name="quick_settings_nfc_on" msgid="1004976611203202230">"CCP activée"</string> <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Enregistrement de l\'écran"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Démarrer"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Arrêter"</string> @@ -455,7 +455,7 @@ <string name="tap_again" msgid="1315420114387908655">"Toucher de nouveau"</string> <string name="keyguard_unlock" msgid="8031975796351361601">"Balayez l\'écran vers le haut pour ouvrir"</string> <string name="keyguard_retry" msgid="886802522584053523">"Balayez l\'écran vers le haut pour réessayer"</string> - <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Déverrouillez l\'écran pour utiliser la NFC"</string> + <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Déverrouillez l\'écran pour utiliser la CCP"</string> <string name="do_disclosure_generic" msgid="4896482821974707167">"Cet appareil appartient à votre organisation"</string> <string name="do_disclosure_with_name" msgid="2091641464065004091">"Cet appareil appartient à <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string> <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"Cet appareil est fourni par <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string> @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Éloigner du bord et masquer"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Éloigner du bord et afficher"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"basculer"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"Domotique"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Commandes des appareils"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Sélectionnez l\'application pour laquelle ajouter des commandes"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> commande ajoutée.</item> @@ -1146,10 +1146,10 @@ <string name="people_tile_description" msgid="8154966188085545556">"Affichez les messages récents, les appels manqués et les mises à jour d\'état"</string> <string name="people_tile_title" msgid="6589377493334871272">"Conversation"</string> <string name="paused_by_dnd" msgid="7856941866433556428">"Interrompue par la fonctionnalité Ne pas déranger"</string> - <!-- no translation found for new_notification_text_content_description (2915029960094389291) --> - <skip /> + <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> a envoyé un message : <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> a envoyé une image"</string> - <!-- no translation found for new_status_content_description (6046637888641308327) --> + <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> a mis à jour son état : <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <!-- no translation found for person_available (2318599327472755472) --> <skip /> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Un problème est survenu lors de la lecture du niveau de charge de la pile"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Touchez pour en savoir plus"</string> diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml index 6a0fc64bdb99..3ef870471407 100644 --- a/packages/SystemUI/res/values-fr/strings.xml +++ b/packages/SystemUI/res/values-fr/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Rapprocher du bord et masquer"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Éloigner du bord et afficher"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"activer/désactiver"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"Commandes de la maison"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Commandes des appareils"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Sélectionnez l\'appli pour laquelle ajouter des commandes"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> commande ajoutée.</item> @@ -1149,6 +1149,8 @@ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> a envoyé un message : <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> a envoyé une image"</string> <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> a mis à jour son statut : <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <!-- no translation found for person_available (2318599327472755472) --> + <skip /> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Un problème est survenu au niveau de la lecture de votre outil de mesure de batterie"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Appuyer pour en savoir plus"</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Pas d\'alarme définie"</string> diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml index 94fa675b3179..ee23e949ba5a 100644 --- a/packages/SystemUI/res/values-gl/strings.xml +++ b/packages/SystemUI/res/values-gl/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Mover ao bordo e ocultar"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Mover fóra do bordo e mostrar"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"activar/desactivar"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"Controis domóticos"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Control de dispositivos"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Escolle unha aplicación para engadir controis"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="other">Engadíronse <xliff:g id="NUMBER_1">%s</xliff:g> controis.</item> @@ -1149,6 +1149,8 @@ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> enviou unha mensaxe: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> enviou unha imaxe"</string> <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> cambiou de estado: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <!-- no translation found for person_available (2318599327472755472) --> + <skip /> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Produciuse un problema ao ler o medidor da batería"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Toca para obter máis información"</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Sen alarmas postas"</string> diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml index 2236d7d992b0..59eceb7e0338 100644 --- a/packages/SystemUI/res/values-gu/strings.xml +++ b/packages/SystemUI/res/values-gu/strings.xml @@ -669,8 +669,7 @@ <string name="wallet_empty_state_label" msgid="7776761245237530394">"તમારા ફોન વડે વધુ ઝડપી તેમજ સુરક્ષિત ખરીદીઓ કરવાની રીત સેટઅપ કરી લો"</string> <string name="wallet_app_button_label" msgid="7123784239111190992">"બધું બતાવો"</string> <string name="wallet_action_button_label_unlock" msgid="8663239748726774487">"ચુકવણી કરવા માટે અનલૉક કરો"</string> - <!-- no translation found for wallet_secondary_label_no_card (530725155985223497) --> - <skip /> + <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"કોઈ કાર્ડ ઉમેરો"</string> <string name="wallet_secondary_label_updating" msgid="5726130686114928551">"અપડેટ કરી રહ્યાં છીએ"</string> <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ઉપયોગ કરવા માટે અનલૉક કરો"</string> <string name="wallet_error_generic" msgid="257704570182963611">"તમારા કાર્ડની માહિતી મેળવવામાં સમસ્યા આવી હતી, કૃપા કરીને થોડા સમય પછી ફરી પ્રયાસ કરો"</string> @@ -1045,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"કિનારી પર ખસેડો અને છુપાવો"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"કિનારીથી ખસેડો અને બતાવો"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"ટૉગલ કરો"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"ઘરેલું સાધનોનાં નિયંત્રણો"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"ડિવાઇસનાં નિયંત્રણો"</string> <string name="controls_providers_title" msgid="6879775889857085056">"નિયંત્રણો ઉમેરવા માટે ઍપ પસંદ કરો"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> નિયંત્રણ ઉમેર્યું.</item> @@ -1147,10 +1146,10 @@ <string name="people_tile_description" msgid="8154966188085545556">"તાજેતરના સંદેશા, ચૂકી ગયેલા કૉલ અને સ્ટેટસ અપડેટ જુઓ"</string> <string name="people_tile_title" msgid="6589377493334871272">"વાતચીત"</string> <string name="paused_by_dnd" msgid="7856941866433556428">"\'ખલેલ પાડશો નહીં\'ની સુવિધા દ્વારા થોભાવેલું"</string> - <!-- no translation found for new_notification_text_content_description (2915029960094389291) --> - <skip /> + <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> દ્વારા કોઈ સંદેશ મોકલવામાં આવ્યો: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> દ્વારા કોઈ છબી મોકલવામાં આવી"</string> - <!-- no translation found for new_status_content_description (6046637888641308327) --> + <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> દ્વારા નવી સ્ટેટસ અપડેટ પોસ્ટ કરવામાં આવી: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <!-- no translation found for person_available (2318599327472755472) --> <skip /> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"તમારું બૅટરી મીટર વાંચવામાં સમસ્યા આવી"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"વધુ માહિતી માટે ટૅપ કરો"</string> diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml index ff686998dff1..9ae4721d8aa0 100644 --- a/packages/SystemUI/res/values-hi/strings.xml +++ b/packages/SystemUI/res/values-hi/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"एज पर ले जाएं और छिपाएं"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"एज से निकालें और दिखाएं"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"टॉगल करें"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"होम कंट्रोल"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"डिवाइस कंट्रोल"</string> <string name="controls_providers_title" msgid="6879775889857085056">"कंट्रोल जोड़ने के लिए ऐप्लिकेशन चुनें"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> कंट्रोल जोड़ा गया.</item> @@ -1149,6 +1149,7 @@ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> ने एक मैसेज भेजा है: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ने एक इमेज भेजी है"</string> <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> ने स्टेटस अपडेट किया है: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <string name="person_available" msgid="2318599327472755472">"ऑनलाइन हैं"</string> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"आपके डिवाइस के बैटरी मीटर की रीडिंग लेने में समस्या आ रही है"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"ज़्यादा जानकारी के लिए टैप करें"</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"कोई अलार्म सेट नहीं है"</string> diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml index a87790dc1af2..689a435fce62 100644 --- a/packages/SystemUI/res/values-hr/strings.xml +++ b/packages/SystemUI/res/values-hr/strings.xml @@ -1049,7 +1049,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Premjesti na rub i sakrij"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Ukloni s ruba i prikaži"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"promijeni"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"Upravljanje kuć. uređajima"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Kontrole uređaja"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Odabir aplikacije za dodavanje kontrola"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="one">Dodana je <xliff:g id="NUMBER_1">%s</xliff:g> kontrola.</item> @@ -1155,6 +1155,7 @@ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> šalje poruku: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"Korisnik <xliff:g id="NAME">%1$s</xliff:g> poslao je sliku"</string> <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> ima ažuriranje statusa: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <string name="person_available" msgid="2318599327472755472">"Dostupan/dostupna"</string> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problem s očitavanjem mjerača baterije"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Dodirnite za više informacija"</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Nema nijednog alarma"</string> diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml index f954f244ca4c..d3c9f6fa2f26 100644 --- a/packages/SystemUI/res/values-hu/strings.xml +++ b/packages/SystemUI/res/values-hu/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Áthelyezés a szélen kívül és elrejtés"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Áthelyezés a szélen kívül és mutatás"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"váltás"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"Otthon vezérlése"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Eszközvezérlők"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Válasszon alkalmazást a vezérlők hozzáadásához"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> vezérlő hozzáadva.</item> @@ -1149,6 +1149,8 @@ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> üzenetet küldött: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> képet küldött"</string> <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> frissítette állapotát: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <!-- no translation found for person_available (2318599327472755472) --> + <skip /> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Probléma merült fel az akkumulátor-töltésmérő olvasásakor"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Koppintással további információkat érhet el."</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Nincs ébresztés"</string> diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml index fd81c4fde903..4605a98dc5f5 100644 --- a/packages/SystemUI/res/values-hy/strings.xml +++ b/packages/SystemUI/res/values-hy/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Տեղափոխել եզրից դուրս և թաքցնել"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Տեղափոխել եզրից դուրս և ցուցադրել"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"միացնել/անջատել"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"Խելացի տուն"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Սարքերի կառավարման տարրեր"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Ընտրեք հավելված` կառավարման տարրեր ավելացնելու համար"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="one">Ավելացվեց կառավարման <xliff:g id="NUMBER_1">%s</xliff:g> տարր։</item> @@ -1149,6 +1149,7 @@ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> օգտատերը հաղորդագրություն է ուղարկել. «<xliff:g id="NOTIFICATION">%2$s</xliff:g>»"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> օգտատերը պատկեր է ուղարկել"</string> <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> օգտատերը նոր կարգավիճակ է հրապարակել. «<xliff:g id="STATUS">%2$s</xliff:g>»"</string> + <string name="person_available" msgid="2318599327472755472">"Հասանելի է"</string> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Մարտկոցի ցուցիչի ցուցմունքը կարդալու հետ կապված խնդիր կա"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Հպեք՝ ավելին իմանալու համար"</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Զարթուցիչ դրված չէ"</string> diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml index 220656f40981..227bf4d22d3e 100644 --- a/packages/SystemUI/res/values-in/strings.xml +++ b/packages/SystemUI/res/values-in/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Pindahkan ke tepi dan sembunyikan"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Pindahkan dari tepi dan tampilkan"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"alihkan"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"Kontrol rumah"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Kontrol perangkat"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Pilih aplikasi untuk menambahkan kontrol"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> kontrol ditambahkan.</item> @@ -1149,6 +1149,8 @@ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> mengirim pesan: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> mengirim gambar"</string> <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> memposting pembaruan status: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <!-- no translation found for person_available (2318599327472755472) --> + <skip /> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Terjadi masalah saat membaca indikator baterai"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Ketuk untuk informasi selengkapnya"</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Alarm tidak disetel"</string> diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml index a0df4b980762..e65097ef288c 100644 --- a/packages/SystemUI/res/values-is/strings.xml +++ b/packages/SystemUI/res/values-is/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Færa að jaðri og fela"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Færa að jaðri og birta"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"kveikja/slökkva"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"Heimastýringar"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Tækjastjórnun"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Veldu forrit til að bæta við stýringum"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> stýringu bætt við.</item> @@ -1149,6 +1149,8 @@ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> sendi skilaboð: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> sendi mynd"</string> <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> er með stöðuuppfærslu: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <!-- no translation found for person_available (2318599327472755472) --> + <skip /> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Vandamál við að lesa stöðu rafhlöðu"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Ýttu til að fá frekari upplýsingar"</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Enginn vekjari"</string> diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml index 871a97c30214..42e5deaa663a 100644 --- a/packages/SystemUI/res/values-it/strings.xml +++ b/packages/SystemUI/res/values-it/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Sposta fino a bordo e nascondi"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Sposta fuori da bordo e mostra"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"attiva/disattiva"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"Controlli della casa"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Controllo dei dispositivi"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Scegli un\'app per aggiungere controlli"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> controlli aggiunti.</item> @@ -1149,6 +1149,7 @@ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> ha inviato un messaggio: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ha inviato un\'immagine"</string> <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> ha aggiornato lo stato: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <string name="person_available" msgid="2318599327472755472">"Disponibile"</string> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problema durante la lettura dell\'indicatore di livello della batteria"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Tocca per ulteriori informazioni"</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Nessuna sveglia"</string> diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml index a23594cc25b7..65c23d47e043 100644 --- a/packages/SystemUI/res/values-iw/strings.xml +++ b/packages/SystemUI/res/values-iw/strings.xml @@ -1054,7 +1054,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"העברה לשוליים והסתרה"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"העברה מהשוליים והצגה"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"החלפת מצב"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"פקדי הבית החכם"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"פקדי מכשירים"</string> <string name="controls_providers_title" msgid="6879775889857085056">"יש לבחור אפליקציה כדי להוסיף פקדים"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="two">נוספו <xliff:g id="NUMBER_1">%s</xliff:g> פקדים.</item> @@ -1158,10 +1158,10 @@ <string name="people_tile_description" msgid="8154966188085545556">"ההודעות האחרונות, שיחות שלא נענו ועדכוני סטטוס"</string> <string name="people_tile_title" msgid="6589377493334871272">"שיחה"</string> <string name="paused_by_dnd" msgid="7856941866433556428">"ההתראה הושהתה על ידי \'נא לא להפריע\'"</string> - <!-- no translation found for new_notification_text_content_description (2915029960094389291) --> - <skip /> + <string name="new_notification_text_content_description" msgid="2915029960094389291">"התקבלה הודעה מ<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> שלח/ה תמונה"</string> - <!-- no translation found for new_status_content_description (6046637888641308327) --> + <string name="new_status_content_description" msgid="6046637888641308327">"הסטטוס של <xliff:g id="NAME">%1$s</xliff:g> עודכן: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <!-- no translation found for person_available (2318599327472755472) --> <skip /> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"בעיה בקריאת מדדי הסוללה"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"יש להקיש כדי להציג מידע נוסף"</string> diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml index 9e3c6167eaf5..d638ace6b459 100644 --- a/packages/SystemUI/res/values-ja/strings.xml +++ b/packages/SystemUI/res/values-ja/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"端に移動して非表示"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"端から移動して表示"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"切り替え"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"ホーム コントロール"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"デバイス コントロール"</string> <string name="controls_providers_title" msgid="6879775889857085056">"コントロールを追加するアプリの選択"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> 件のコントロールを追加しました。</item> @@ -1149,6 +1149,7 @@ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> さんからのメッセージ: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> さんが画像を送信しました"</string> <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> さんの近況: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <string name="person_available" msgid="2318599327472755472">"オンライン"</string> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"バッテリー残量の読み込み中に問題が発生しました"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"タップすると詳細が表示されます"</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"アラーム未設定"</string> diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml index c4545d42a01e..5ce3fe571bdd 100644 --- a/packages/SystemUI/res/values-ka/strings.xml +++ b/packages/SystemUI/res/values-ka/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"კიდეში გადატანა და დამალვა"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"კიდეში გადატანა და გამოჩენა"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"გადართვა"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"სახლის მართვის საშუალებები"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"მოწყობილ. მართვის საშუალებები"</string> <string name="controls_providers_title" msgid="6879775889857085056">"აირჩიეთ აპი მართვის საშუალებების დასამატებლად"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="other">დაემატა <xliff:g id="NUMBER_1">%s</xliff:g> მართვის საშუალება.</item> @@ -1146,10 +1146,10 @@ <string name="people_tile_description" msgid="8154966188085545556">"ბოლოდროინდელი შეტყობინებების, გამოტოვებული ზარების და სტატუსის განახლებების ნახვა"</string> <string name="people_tile_title" msgid="6589377493334871272">"მიმოწერა"</string> <string name="paused_by_dnd" msgid="7856941866433556428">"დაპაუზებულია ფუნქციის „არ შემაწუხოთ“ მიერ"</string> - <!-- no translation found for new_notification_text_content_description (2915029960094389291) --> - <skip /> + <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g>-მა გაგზავნა შეტყობინება: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g>-მ(ა) სურათი გამოგზავნა"</string> - <!-- no translation found for new_status_content_description (6046637888641308327) --> + <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g>-მა განაახლა სტატუსი: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <!-- no translation found for person_available (2318599327472755472) --> <skip /> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"თქვენი ბატარეის მზომის წაკითხვასთან დაკავშირებით პრობლემა დაფიქსირდა"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"შეეხეთ მეტი ინფორმაციისთვის"</string> diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml index 445483ddd62d..cba176d5953b 100644 --- a/packages/SystemUI/res/values-kk/strings.xml +++ b/packages/SystemUI/res/values-kk/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Шетке жылжыту және жасыру"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Шетке жылжыту және көрсету"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"ауыстыру"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"Үйді басқару элементтері"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Құрылғыны басқару элементтері"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Басқару элементтері қосылатын қолданбаны таңдаңыз"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> басқару элементі енгізілді.</item> @@ -1146,10 +1146,10 @@ <string name="people_tile_description" msgid="8154966188085545556">"Соңғы хабарларды, өткізіп алған қоңыраулар мен жаңартылған күйлерді көруге болады."</string> <string name="people_tile_title" msgid="6589377493334871272">"Әңгіме"</string> <string name="paused_by_dnd" msgid="7856941866433556428">"Мазаламау режимі арқылы кідіртілді."</string> - <!-- no translation found for new_notification_text_content_description (2915029960094389291) --> - <skip /> + <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> хабар жіберді: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> сурет жіберді."</string> - <!-- no translation found for new_status_content_description (6046637888641308327) --> + <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> ағымдағы күйін жаңартты: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <!-- no translation found for person_available (2318599327472755472) --> <skip /> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Батарея зарядының дерегі алынбай жатыр"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Толығырақ ақпарат алу үшін түртіңіз."</string> diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml index 87ecbbebbe28..1d4b5153210b 100644 --- a/packages/SystemUI/res/values-km/strings.xml +++ b/packages/SystemUI/res/values-km/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"ផ្លាស់ទីទៅផ្នែកខាងចុង រួចលាក់"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"ផ្លាស់ទីចេញពីផ្នែកខាងចុង រួចបង្ហាញ"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"បិទ/បើក"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"ការគ្រប់គ្រងផ្ទះ"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"ផ្ទាំងគ្រប់គ្រងឧបករណ៍"</string> <string name="controls_providers_title" msgid="6879775889857085056">"ជ្រើសរើសកម្មវិធីដែលត្រូវបញ្ចូលផ្ទាំងគ្រប់គ្រង"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="other">បានបញ្ចូលការគ្រប់គ្រង <xliff:g id="NUMBER_1">%s</xliff:g>។</item> @@ -1146,11 +1146,10 @@ <string name="people_tile_description" msgid="8154966188085545556">"មើលព័ត៌មានថ្មីៗអំពីស្ថានភាព ការខកខានទទួល និងសារថ្មីៗ"</string> <string name="people_tile_title" msgid="6589377493334871272">"ការសន្ទនា"</string> <string name="paused_by_dnd" msgid="7856941866433556428">"បានផ្អាកដោយមុខងារកុំរំខាន"</string> - <!-- no translation found for new_notification_text_content_description (2915029960094389291) --> - <skip /> + <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> បានផ្ញើសារ៖ <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> បានផ្ញើរូបភាព"</string> - <!-- no translation found for new_status_content_description (6046637888641308327) --> - <skip /> + <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> មានបច្ចុប្បន្នភាពស្ថានភាព៖ <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <string name="person_available" msgid="2318599327472755472">"មាន"</string> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"មានបញ្ហាក្នុងការអានឧបករណ៍រង្វាស់កម្រិតថ្មរបស់អ្នក"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"ចុចដើម្បីទទួលបានព័ត៌មានបន្ថែម"</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"មិនបានកំណត់ម៉ោងរោទ៍ទេ"</string> diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml index 8962ff4d2277..cc6b15372e92 100644 --- a/packages/SystemUI/res/values-kn/strings.xml +++ b/packages/SystemUI/res/values-kn/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"ಅಂಚಿಗೆ ಸರಿಸಿ ಮತ್ತು ಮರೆಮಾಡಿ"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"ಅಂಚನ್ನು ಸರಿಸಿ ಮತ್ತು ತೋರಿಸಿ"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"ಟಾಗಲ್ ಮಾಡಿ"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"ಹೋಮ್ ನಿಯಂತ್ರಣಗಳು"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"ಸಾಧನ ನಿಯಂತ್ರಣಗಳು"</string> <string name="controls_providers_title" msgid="6879775889857085056">"ನಿಯಂತ್ರಣಗಳನ್ನು ಸೇರಿಸಲು ಆ್ಯಪ್ ಅನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> ನಿಯಂತ್ರಣಗಳನ್ನು ಸೇರಿಸಲಾಗಿದೆ.</item> @@ -1146,10 +1146,10 @@ <string name="people_tile_description" msgid="8154966188085545556">"ಇತ್ತೀಚಿನ ಸಂದೇಶಗಳು, ಮಿಸ್ಡ್ ಕಾಲ್ಗಳು ಮತ್ತು ಸ್ಥಿತಿ ಅಪ್ಡೇಟ್ಗಳು"</string> <string name="people_tile_title" msgid="6589377493334871272">"ಸಂಭಾಷಣೆ"</string> <string name="paused_by_dnd" msgid="7856941866433556428">"\'ಅಡಚಣೆ ಮಾಡಬೇಡಿ\' ನಿಂದ ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ"</string> - <!-- no translation found for new_notification_text_content_description (2915029960094389291) --> - <skip /> + <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> ಅವರು ಸಂದೇಶವನ್ನು ಕಳುಹಿಸಿದ್ದಾರೆ: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ಅವರು ಚಿತ್ರವನ್ನು ಕಳುಹಿಸಿದ್ದಾರೆ"</string> - <!-- no translation found for new_status_content_description (6046637888641308327) --> + <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> ಅವರು ಸ್ಥಿತಿಯ ಅಪ್ಡೇಟ್ ಹೊಂದಿದ್ದಾರೆ: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <!-- no translation found for person_available (2318599327472755472) --> <skip /> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"ನಿಮ್ಮ ಬ್ಯಾಟರಿ ಮೀಟರ್ ಓದುವಾಗ ಸಮಸ್ಯೆ ಎದುರಾಗಿದೆ"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"ಇನ್ನಷ್ಟು ಮಾಹಿತಿಗಾಗಿ ಟ್ಯಾಪ್ ಮಾಡಿ"</string> diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml index 1d470728d7e6..20a7c5f1545c 100644 --- a/packages/SystemUI/res/values-ko/strings.xml +++ b/packages/SystemUI/res/values-ko/strings.xml @@ -1034,9 +1034,9 @@ <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"전체 화면 확대"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"화면 일부 확대"</string> <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"전환"</string> - <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"접근성 동작이 접근성 버튼으로 대체되었습니다\n\n"<annotation id="link">"설정 보기"</annotation></string> + <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"접근성 동작이 접근성 버튼으로 대체되었습니다.\n\n"<annotation id="link">"설정 보기"</annotation></string> <string name="accessibility_floating_button_switch_migration_tooltip" msgid="6248529129221218770">"접근성 동작을 버튼으로 전환할 수 있습니다.\n\n"<annotation id="link">"설정"</annotation></string> - <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"버튼을 가장자리로 옮겨서 일시적으로 숨기세요"</string> + <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"버튼을 가장자리로 옮겨서 일시적으로 숨기세요."</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"왼쪽 상단으로 이동"</string> <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"오른쪽 상단으로 이동"</string> <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"왼쪽 하단으로 이동"</string> @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"가장자리로 옮겨서 숨기기"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"가장자리 바깥으로 옮겨서 표시"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"전환"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"홈 컨트롤"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"기기 컨트롤"</string> <string name="controls_providers_title" msgid="6879775889857085056">"컨트롤을 추가할 앱을 선택하세요"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="other">제어 기능 <xliff:g id="NUMBER_1">%s</xliff:g>개가 추가되었습니다.</item> @@ -1146,10 +1146,10 @@ <string name="people_tile_description" msgid="8154966188085545556">"최근 메시지, 부재중 전화, 상태 업데이트 보기"</string> <string name="people_tile_title" msgid="6589377493334871272">"대화"</string> <string name="paused_by_dnd" msgid="7856941866433556428">"방해 금지 모드로 인해 일시중지됨"</string> - <!-- no translation found for new_notification_text_content_description (2915029960094389291) --> - <skip /> + <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g>님이 메시지를 보냈습니다: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g>님이 이미지를 보냈습니다."</string> - <!-- no translation found for new_status_content_description (6046637888641308327) --> + <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g>님의 상태가 업데이트되었습니다: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <!-- no translation found for person_available (2318599327472755472) --> <skip /> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"배터리 수준을 읽는 중에 문제가 발생함"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"탭하여 자세한 정보를 확인하세요."</string> diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml index c0c42c30b108..34d799c2a25b 100644 --- a/packages/SystemUI/res/values-ky/strings.xml +++ b/packages/SystemUI/res/values-ky/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Ичине жылдырып, көрсөтүңүз"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Сыртка жылдырып, көрсөтүңүз"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"өчүрүү/күйгүзүү"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"Үйдү башкаруу элементтери"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Түзмөктү башкаруу элементтери"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Башкаруу элементтери кошула турган колдонмону тандоо"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> башкаруу элементи кошулду.</item> @@ -1146,10 +1146,10 @@ <string name="people_tile_description" msgid="8154966188085545556">"Акыркы билдирүүлөрдү, жооп берилбеген чалууларды жана статустардын жаңырганын көрөсүз"</string> <string name="people_tile_title" msgid="6589377493334871272">"Сүйлөшүү"</string> <string name="paused_by_dnd" msgid="7856941866433556428">"\"Тынчымды алба\" режими тындырды"</string> - <!-- no translation found for new_notification_text_content_description (2915029960094389291) --> - <skip /> + <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> билдирүү жөнөттү: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> сүрөт жөнөттү"</string> - <!-- no translation found for new_status_content_description (6046637888641308327) --> + <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> жаңы абалы тууралуу жарыялады: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <!-- no translation found for person_available (2318599327472755472) --> <skip /> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Батареяңыздын кубаты аныкталбай жатат"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Кеңири маалымат алуу үчүн таптап коюңуз"</string> diff --git a/packages/SystemUI/res/values-land-television/dimens.xml b/packages/SystemUI/res/values-land-television/dimens.xml index a9bc9e5cd638..8fc46125b477 100644 --- a/packages/SystemUI/res/values-land-television/dimens.xml +++ b/packages/SystemUI/res/values-land-television/dimens.xml @@ -22,7 +22,7 @@ <dimen name="volume_dialog_panel_transparent_padding">24dp</dimen> <dimen name="volume_dialog_slider_width">4dp</dimen> <dimen name="volume_dialog_slider_corner_radius">@dimen/volume_dialog_slider_width</dimen> - <dimen name="volume_dialog_background_blur_radius">100dp</dimen> + <dimen name="volume_dialog_background_blur_radius">31dp</dimen> <dimen name="volume_tool_tip_right_margin">136dp</dimen> <dimen name="tv_volume_dialog_bubble_size">36dp</dimen> diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml index f47b8e8a2dc2..8a47dddce06f 100644 --- a/packages/SystemUI/res/values-lo/strings.xml +++ b/packages/SystemUI/res/values-lo/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"ຍ້າຍອອກຂອບ ແລະ ເຊື່ອງ"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"ຍ້າຍອອກຂອບ ແລະ ສະແດງ"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"ສະຫຼັບ"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"ການຄວບຄຸມເຮືອນ"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"ການຄວບຄຸມອຸປະກອນ"</string> <string name="controls_providers_title" msgid="6879775889857085056">"ເລືອກແອັບເພື່ອເພີ່ມການຄວບຄຸມ"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="other">ເພີ່ມ <xliff:g id="NUMBER_1">%s</xliff:g> ການຄວບຄຸມແລ້ວ.</item> @@ -1149,6 +1149,8 @@ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> ສົ່ງຂໍ້ຄວາມ: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ສົ່ງຮູບພາບແລ້ວ"</string> <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> ອັບເດດສະຖານະ: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <!-- no translation found for person_available (2318599327472755472) --> + <skip /> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"ເກີດບັນຫາໃນການອ່ານຕົວວັດແທກແບັດເຕີຣີຂອງທ່ານ"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"ແຕະເພື່ອເບິ່ງຂໍ້ມູນເພີ່ມເຕີມ"</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"ບໍ່ໄດ້ຕັ້ງໂມງປຸກ"</string> diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml index e12afb555a41..11d363ed59ef 100644 --- a/packages/SystemUI/res/values-lt/strings.xml +++ b/packages/SystemUI/res/values-lt/strings.xml @@ -1054,7 +1054,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Perkelti į kraštą ir slėpti"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Perkelti iš krašto ir rodyti"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"perjungti"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"Namų sistemos valdikliai"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Įrenginio valdikliai"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Pasirinkite programą, kad pridėtumėte valdiklių"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="one">Pridėtas <xliff:g id="NUMBER_1">%s</xliff:g> valdiklis.</item> @@ -1161,6 +1161,8 @@ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> išsiuntė pranešimą: „<xliff:g id="NOTIFICATION">%2$s</xliff:g>“"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> išsiuntė vaizdą"</string> <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> atnaujino būseną: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <!-- no translation found for person_available (2318599327472755472) --> + <skip /> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Nuskaitant akumuliatoriaus skaitiklį iškilo problema"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Palieskite, kad sužinotumėte daugiau informacijos"</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Nenustatyta signalų"</string> diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml index 1d0b0fffb6b8..63f85fb4c76d 100644 --- a/packages/SystemUI/res/values-lv/strings.xml +++ b/packages/SystemUI/res/values-lv/strings.xml @@ -1049,7 +1049,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Pārvietot uz malu un paslēpt"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Pārvietot no malas un parādīt"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"pārslēgt"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"Mājas kontrolierīces"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Ierīču vadīklas"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Izvēlieties lietotni, lai pievienotu vadīklas"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="zero">Pievienotas <xliff:g id="NUMBER_1">%s</xliff:g> vadīklas.</item> @@ -1155,6 +1155,8 @@ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> nosūtīja ziņojumu: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> nosūtīja attēlu"</string> <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> atjaunināja statusu: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <!-- no translation found for person_available (2318599327472755472) --> + <skip /> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Nevar iegūt informāciju par akumulatora uzlādes līmeni."</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Pieskarieties, lai iegūtu plašāku informāciju."</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Nav iestatīts signāls"</string> diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml index 3bfc4337e7b9..5392d52526f3 100644 --- a/packages/SystemUI/res/values-mk/strings.xml +++ b/packages/SystemUI/res/values-mk/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Премести до работ и сокриј"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Премести над работ и прикажи"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"вклучување/исклучување"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"Контроли за домот"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Контроли за уредите"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Изберете апликација за да додадете контроли"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="one">Додадена е <xliff:g id="NUMBER_1">%s</xliff:g> контрола.</item> @@ -1146,10 +1146,10 @@ <string name="people_tile_description" msgid="8154966188085545556">"Видете ги неодамнешните пораки, пропуштени повици и промени на статусот"</string> <string name="people_tile_title" msgid="6589377493334871272">"Разговор"</string> <string name="paused_by_dnd" msgid="7856941866433556428">"Паузирано од „Не вознемирувај“"</string> - <!-- no translation found for new_notification_text_content_description (2915029960094389291) --> - <skip /> + <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> испрати порака: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> испрати слика"</string> - <!-- no translation found for new_status_content_description (6046637888641308327) --> + <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> има ажурирање на статусот: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <!-- no translation found for person_available (2318599327472755472) --> <skip /> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Проблем при читањето на мерачот на батеријата"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Допрете за повеќе информации"</string> diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml index a18780bb7511..cdb3a69144f6 100644 --- a/packages/SystemUI/res/values-ml/strings.xml +++ b/packages/SystemUI/res/values-ml/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"എഡ്ജിലേക്ക് നീക്കി മറയ്ക്കുക"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"എഡ്ജിൽ നിന്ന് നീക്കി കാണിക്കൂ"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"മാറ്റുക"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"ഹോം കൺട്രോളുകൾ"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"ഉപകരണ നിയന്ത്രണങ്ങൾ"</string> <string name="controls_providers_title" msgid="6879775889857085056">"നിയന്ത്രണങ്ങൾ ചേർക്കാൻ ആപ്പ് തിരഞ്ഞെടുക്കുക"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> നിയന്ത്രണങ്ങൾ ചേർത്തു.</item> @@ -1146,11 +1146,10 @@ <string name="people_tile_description" msgid="8154966188085545556">"അടുത്തിടെയുള്ള സന്ദേശങ്ങൾ, മിസ്ഡ് കോൾ, സ്റ്റാറ്റസ് അപ്ഡേറ്റുകൾ എന്നിവ കാണൂ"</string> <string name="people_tile_title" msgid="6589377493334871272">"സംഭാഷണം"</string> <string name="paused_by_dnd" msgid="7856941866433556428">"\'ശല്യപ്പെടുത്തരുത്\' ഓണായതിനാൽ തൽക്കാലം നിർത്തി"</string> - <!-- no translation found for new_notification_text_content_description (2915029960094389291) --> - <skip /> + <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> ഒരു സന്ദേശം അയച്ചു: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g>, ഒരു ചിത്രം അയച്ചു"</string> - <!-- no translation found for new_status_content_description (6046637888641308327) --> - <skip /> + <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> എന്നയാൾ സ്റ്റാറ്റസ് അപ്ഡേറ്റ് ചെയ്തു: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <string name="person_available" msgid="2318599327472755472">"ലഭ്യമാണ്"</string> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"നിങ്ങളുടെ ബാറ്ററി മീറ്റർ വായിക്കുന്നതിൽ പ്രശ്നമുണ്ട്"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"കൂടുതൽ വിവരങ്ങൾക്ക് ടാപ്പ് ചെയ്യുക"</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"അലാറം സജ്ജീകരിച്ചിട്ടില്ല"</string> diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml index 9fe4d0aab82a..d16e479dbc2a 100644 --- a/packages/SystemUI/res/values-mn/strings.xml +++ b/packages/SystemUI/res/values-mn/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Ирмэг рүү зөөж, нуух"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Ирмэгээс гаргаж, харуулах"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"асаах/унтраах"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"Гэрийн удирдлагууд"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Төхөөрөмжийн хяналт"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Хяналтууд нэмэхийн тулд аппыг сонгоно уу"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> хяналтыг нэмлээ.</item> @@ -1149,6 +1149,7 @@ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> мессеж илгээсэн: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> зураг илгээсэн"</string> <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> төлөвийн шинэчлэлт хийсэн байна: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <string name="person_available" msgid="2318599327472755472">"Боломжтой"</string> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Таны батарей хэмжигчийг уншихад асуудал гарлаа"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Нэмэлт мэдээлэл авахын тулд товшино уу"</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Сэрүүлэг тавиагүй"</string> diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml index 5a4039e51920..bf27df9c63f9 100644 --- a/packages/SystemUI/res/values-mr/strings.xml +++ b/packages/SystemUI/res/values-mr/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"एजवर हलवा आणि लपवा"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"एजवर हलवा आणि दाखवा"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"टॉगल करा"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"होम कंट्रोल"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"डिव्हाइस नियंत्रणे"</string> <string name="controls_providers_title" msgid="6879775889857085056">"नियंत्रणे जोडण्यासाठी ॲप निवडा"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> नियंत्रणे जोडली.</item> @@ -1146,10 +1146,10 @@ <string name="people_tile_description" msgid="8154966188085545556">"अलीकडील मेसेज, मिस्ड कॉल आणि स्टेटस अपडेट पाहा"</string> <string name="people_tile_title" msgid="6589377493334871272">"संभाषण"</string> <string name="paused_by_dnd" msgid="7856941866433556428">"व्यत्यय आणू नका द्वारे थांबवले गेले"</string> - <!-- no translation found for new_notification_text_content_description (2915029960094389291) --> - <skip /> + <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> यांनी मेसेज पाठवला: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> यांनी इमेज पाठवली"</string> - <!-- no translation found for new_status_content_description (6046637888641308327) --> + <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> यांनी स्टेटस अपडेट केले: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <!-- no translation found for person_available (2318599327472755472) --> <skip /> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"तुमचे बॅटरी मीटर वाचताना समस्या आली"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"अधिक माहितीसाठी टॅप करा"</string> diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml index 9295805f3f80..1d16edcdc49c 100644 --- a/packages/SystemUI/res/values-ms/strings.xml +++ b/packages/SystemUI/res/values-ms/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Alihkan ke tepi dan sorokkan"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Alihkan ke tepi dan tunjukkan"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"togol"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"Kawalan rumah"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Kawalan peranti"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Pilih apl untuk menambahkan kawalan"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> kawalan ditambah.</item> @@ -1146,10 +1146,10 @@ <string name="people_tile_description" msgid="8154966188085545556">"Lihat mesej terbaharu, panggilan terlepas dan kemaskinian status"</string> <string name="people_tile_title" msgid="6589377493334871272">"Perbualan"</string> <string name="paused_by_dnd" msgid="7856941866433556428">"Dijeda oleh Jangan Ganggu"</string> - <!-- no translation found for new_notification_text_content_description (2915029960094389291) --> - <skip /> + <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> menghantar mesej: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> menghantar imej"</string> - <!-- no translation found for new_status_content_description (6046637888641308327) --> + <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> mempunyai kemaskinian status: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <!-- no translation found for person_available (2318599327472755472) --> <skip /> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Masalah membaca meter bateri anda"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Ketik untuk mendapatkan maklumat lanjut"</string> diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml index 51c800f697e1..c92a45e8dbcc 100644 --- a/packages/SystemUI/res/values-my/strings.xml +++ b/packages/SystemUI/res/values-my/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"အစွန်းသို့ရွှေ့ပြီး ဝှက်ရန်"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"အစွန်းမှရွှေ့ပြီး ပြရန်"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"ပြောင်းရန်"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"ပင်မ ထိန်းချုပ်မှုများ"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"စက်ထိန်းစနစ်"</string> <string name="controls_providers_title" msgid="6879775889857085056">"ထိန်းချုပ်မှုများထည့်ရန် အက်ပ်ရွေးခြင်း"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="other">ခလုတ် <xliff:g id="NUMBER_1">%s</xliff:g> ခု ထည့်လိုက်သည်။</item> @@ -1149,6 +1149,7 @@ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> က မက်ဆေ့ဂျ်ပို့လိုက်သည်- <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> က ပုံပို့လိုက်သည်"</string> <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> က အခြေအနေ အပ်ဒိတ်လုပ်လိုက်သည်- <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <string name="person_available" msgid="2318599327472755472">"ချိတ်ဆက်နိုင်သည်"</string> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"သင်၏ ဘက်ထရီမီတာကို ဖတ်ရာတွင် ပြဿနာရှိနေသည်"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"နောက်ထပ်အချက်အလက်များအတွက် တို့ပါ"</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"နှိုးစက်ပေးမထားပါ"</string> diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml index 69d636d1121c..a0db7794c4ea 100644 --- a/packages/SystemUI/res/values-nb/strings.xml +++ b/packages/SystemUI/res/values-nb/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Flytt til kanten og skjul"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Flytt ut kanten og vis"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"slå av/på"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"Hjemkontroller"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Enhetsstyring"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Velg en app for å legge til kontroller"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> kontroller er lagt til.</item> @@ -1149,6 +1149,7 @@ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> har sendt en melding: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> har sendt et bilde"</string> <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> har en statusoppdatering: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <string name="person_available" msgid="2318599327472755472">"Tilgjengelig"</string> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Kunne ikke lese batterimåleren"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Trykk for å få mer informasjon"</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Ingen alarm angitt"</string> diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml index 8bb7d861e607..ee9b105d881d 100644 --- a/packages/SystemUI/res/values-ne/strings.xml +++ b/packages/SystemUI/res/values-ne/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"किनारामा सार्नुहोस् र नदेखिने पार्नु…"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"किनाराबाट सार्नुहोस् र देखिने पार्नु…"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"टगल गर्नुहोस्"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"घरायसी उपकरणका नियन्त्रणहरू"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"डिभाइस नियन्त्रण गर्ने विजेटहरू"</string> <string name="controls_providers_title" msgid="6879775889857085056">"कन्ट्रोल थप्नु पर्ने एप छान्नुहोस्"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> वटा नियन्त्र थपियो।</item> @@ -1149,6 +1149,7 @@ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> ले एउटा म्यासेज पठाउनुभएको छ: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ले एउटा फोटो पठाउनुभयो"</string> <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> ले स्ट्याटस अपडेट गर्नुभएको छ: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <string name="person_available" msgid="2318599327472755472">"उपलब्ध"</string> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"डिभाइसको ब्याट्रीको मिटर रिडिङ क्रममा समस्या भयो"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"थप जानकारी प्राप्त गर्न ट्याप गर्नुहोस्"</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"अलार्म राखिएको छैन"</string> diff --git a/packages/SystemUI/res/values-night/styles.xml b/packages/SystemUI/res/values-night/styles.xml index e6165ee50076..461505f12ce6 100644 --- a/packages/SystemUI/res/values-night/styles.xml +++ b/packages/SystemUI/res/values-night/styles.xml @@ -42,4 +42,10 @@ <item name="android:textColorPrimary">?android:attr/textColorPrimaryInverse</item> </style> + <style name="Theme.PeopleTileConfigActivity" parent="@style/Theme.SystemUI"> + <item name="android:windowActionBar">false</item> + <item name="android:windowNoTitle">true</item> + <item name="android:windowLightStatusBar">false</item> + </style> + </resources> diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml index c9e869de871d..b74892a39e18 100644 --- a/packages/SystemUI/res/values-nl/strings.xml +++ b/packages/SystemUI/res/values-nl/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Naar rand verplaatsen en verbergen"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Over rand verplaatsen en tonen"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"schakelen"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"Bediening voor in huis"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Apparaatbediening"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Kies de app waaraan je bedieningselementen wilt toevoegen"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> bedieningselementen toegevoegd.</item> @@ -1149,6 +1149,7 @@ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> heeft een bericht gestuurd: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> heeft een afbeelding gestuurd"</string> <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> heeft een statusupdate: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <string name="person_available" msgid="2318599327472755472">"Beschikbaar"</string> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Probleem bij het lezen van je batterijmeter"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Tik hier voor meer informatie"</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Geen wekker gezet"</string> diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml index a209581c50f4..2ad54f7fd75a 100644 --- a/packages/SystemUI/res/values-or/strings.xml +++ b/packages/SystemUI/res/values-or/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"ଧାରକୁ ମୁଭ୍ କରି ଲୁଚାନ୍ତୁ"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"ଧାର ବାହାରକୁ ମୁଭ୍ କରି ଦେଖାନ୍ତୁ"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"ଟୋଗଲ୍ କରନ୍ତୁ"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"ହୋମ୍ କଣ୍ଟ୍ରୋଲ୍"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"ଡିଭାଇସ୍ ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକ"</string> <string name="controls_providers_title" msgid="6879775889857085056">"ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକୁ ଯୋଗ କରିବାକୁ ଆପ୍ ବାଛନ୍ତୁ"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g>ଟି ନିୟନ୍ତ୍ରଣ ଯୋଗ କରାଯାଇଛି।</item> @@ -1149,6 +1149,8 @@ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> ଏକ ମେସେଜ୍ ପଠାଇଛନ୍ତି: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ଏକ ଛବି ପଠାଇଛନ୍ତି"</string> <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> ଏକ ସ୍ଥିତି ଅପଡେଟ୍ କରିଛନ୍ତି: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <!-- no translation found for person_available (2318599327472755472) --> + <skip /> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"ଆପଣଙ୍କ ବ୍ୟାଟେରୀ ମିଟର୍ ପଢ଼ିବାରେ ସମସ୍ୟା ହେଉଛି"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"ଅଧିକ ସୂଚନା ପାଇଁ ଟାପ୍ କରନ୍ତୁ"</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"ଆଲାରାମ ସେଟ୍ ହୋଇନାହିଁ"</string> diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml index 49b1f9a54689..3f2e4810dbd2 100644 --- a/packages/SystemUI/res/values-pa/strings.xml +++ b/packages/SystemUI/res/values-pa/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"ਕਿਨਾਰੇ ਵਿੱਚ ਲਿਜਾ ਕੇ ਲੁਕਾਓ"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"ਕਿਨਾਰੇ ਤੋਂ ਬਾਹਰ ਕੱਢ ਕੇ ਦਿਖਾਓ"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"ਟੌਗਲ ਕਰੋ"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"ਹੋਮ ਕੰਟਰੋਲ"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"ਡੀਵਾਈਸ ਕੰਟਰੋਲ"</string> <string name="controls_providers_title" msgid="6879775889857085056">"ਕੰਟਰੋਲ ਸ਼ਾਮਲ ਕਰਨ ਲਈ ਐਪ ਚੁਣੋ"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> ਕੰਟਰੋਲ ਸ਼ਾਮਲ ਕੀਤਾ ਗਿਆ।</item> @@ -1146,10 +1146,10 @@ <string name="people_tile_description" msgid="8154966188085545556">"ਹਾਲੀਆ ਸੁਨੇਹੇ, ਮਿਸ ਕਾਲਾਂ ਅਤੇ ਸਥਿਤੀ ਸੰਬੰਧੀ ਅੱਪਡੇਟ ਦੇਖੋ"</string> <string name="people_tile_title" msgid="6589377493334871272">"ਗੱਲਬਾਤ"</string> <string name="paused_by_dnd" msgid="7856941866433556428">"\'ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ\' ਵਿਸ਼ੇਸ਼ਤਾ ਨੇ ਰੋਕ ਦਿੱਤਾ"</string> - <!-- no translation found for new_notification_text_content_description (2915029960094389291) --> - <skip /> + <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> ਨੇ ਸੁਨੇਹਾ ਭੇਜਿਆ: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ਨੇ ਇੱਕ ਚਿੱਤਰ ਭੇਜਿਆ ਹੈ"</string> - <!-- no translation found for new_status_content_description (6046637888641308327) --> + <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> ਨੇ ਸਥਿਤੀ ਅੱਪਡੇਟ ਕੀਤੀ ਹੈ: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <!-- no translation found for person_available (2318599327472755472) --> <skip /> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"ਤੁਹਾਡੇ ਬੈਟਰੀ ਮੀਟਰ ਨੂੰ ਪੜ੍ਹਨ ਵਿੱਚ ਸਮੱਸਿਆ ਹੋ ਰਹੀ ਹੈ"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"ਹੋਰ ਜਾਣਕਾਰੀ ਲਈ ਟੈਪ ਕਰੋ"</string> diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml index fb433c5b43ff..990b461fe0f9 100644 --- a/packages/SystemUI/res/values-pl/strings.xml +++ b/packages/SystemUI/res/values-pl/strings.xml @@ -1054,7 +1054,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Przenieś do krawędzi i ukryj"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Przenieś poza krawędź i pokaż"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"przełącz"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"Sterowanie domem"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Sterowanie urządzeniami"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Wybierz aplikację, do której chcesz dodać elementy sterujące"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="few">Dodano <xliff:g id="NUMBER_1">%s</xliff:g> elementy sterujące</item> @@ -1161,6 +1161,7 @@ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> wysyła wiadomość: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> wysyła zdjęcie"</string> <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> ma nowy stan: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <string name="person_available" msgid="2318599327472755472">"Użytkownik dostępny"</string> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problem z odczytaniem pomiaru wykorzystania baterii"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Kliknij, aby uzyskać więcej informacji"</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Nie ustawiono alarmu"</string> diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml index e33c106c7420..2755508efcf4 100644 --- a/packages/SystemUI/res/values-pt-rBR/strings.xml +++ b/packages/SystemUI/res/values-pt-rBR/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Mover para a borda e ocultar"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Mover para fora da borda e exibir"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"alternar"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"Automação residencial"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Controles do dispositivo"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Escolha um app para adicionar controles"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> controle adicionado.</item> @@ -1149,6 +1149,7 @@ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> enviou uma mensagem: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> enviou uma imagem"</string> <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> atualizou o status: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <string name="person_available" msgid="2318599327472755472">"Disponível"</string> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problema para ler seu medidor de bateria"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Toque para mais informações"</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Nenhum alarme definido"</string> diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml index 2965cb7eb578..16965af689cc 100644 --- a/packages/SystemUI/res/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res/values-pt-rPT/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Mover p/ extremidade e ocultar"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Retirar extremidade e mostrar"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"ativar/desativar"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"Controlo casa"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Controlos de dispositivos"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Escolha uma app para adicionar controlos"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> controlos adicionados.</item> @@ -1149,6 +1149,8 @@ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> enviou uma mensagem: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> enviou uma imagem"</string> <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> tem uma atualização de estado: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <!-- no translation found for person_available (2318599327472755472) --> + <skip /> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Ocorreu um problema ao ler o medidor da bateria"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Toque para obter mais informações"</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Nenhum alarme defin."</string> diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml index e33c106c7420..2755508efcf4 100644 --- a/packages/SystemUI/res/values-pt/strings.xml +++ b/packages/SystemUI/res/values-pt/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Mover para a borda e ocultar"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Mover para fora da borda e exibir"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"alternar"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"Automação residencial"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Controles do dispositivo"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Escolha um app para adicionar controles"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> controle adicionado.</item> @@ -1149,6 +1149,7 @@ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> enviou uma mensagem: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> enviou uma imagem"</string> <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> atualizou o status: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <string name="person_available" msgid="2318599327472755472">"Disponível"</string> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problema para ler seu medidor de bateria"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Toque para mais informações"</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Nenhum alarme definido"</string> diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml index 622d330da443..346323685e83 100644 --- a/packages/SystemUI/res/values-ro/strings.xml +++ b/packages/SystemUI/res/values-ro/strings.xml @@ -1049,7 +1049,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Mutați în afară și ascundeți"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Mutați în afară și afișați"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"Activați / dezactivați"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"Comenzi pentru locuință"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Comenzile dispozitivelor"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Alegeți aplicația pentru a adăuga comenzi"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="few">S-au adăugat <xliff:g id="NUMBER_1">%s</xliff:g> comenzi.</item> @@ -1152,10 +1152,10 @@ <string name="people_tile_description" msgid="8154966188085545556">"Vedeți mesaje recente, apeluri pierdute și actualizări de stare"</string> <string name="people_tile_title" msgid="6589377493334871272">"Conversație"</string> <string name="paused_by_dnd" msgid="7856941866433556428">"Întrerupt de Nu deranja"</string> - <!-- no translation found for new_notification_text_content_description (2915029960094389291) --> - <skip /> + <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> a trimis un mesaj: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> a trimis o imagine"</string> - <!-- no translation found for new_status_content_description (6046637888641308327) --> + <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> are o nouă stare: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <!-- no translation found for person_available (2318599327472755472) --> <skip /> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problemă la citirea măsurării bateriei"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Atingeți pentru mai multe informații"</string> diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml index 30c757e8da96..8b0d70e4a8e4 100644 --- a/packages/SystemUI/res/values-ru/strings.xml +++ b/packages/SystemUI/res/values-ru/strings.xml @@ -1054,7 +1054,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Перенести к краю и скрыть"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Вернуть из-за края и показать"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"включить или отключить"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"Автоматизация дома"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Управление устройствами"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Чтобы добавить виджеты управления, выберите приложение"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="one">Добавлен <xliff:g id="NUMBER_1">%s</xliff:g> элемент управления.</item> @@ -1158,10 +1158,10 @@ <string name="people_tile_description" msgid="8154966188085545556">"Будьте в курсе последних сообщений, пропущенных вызовов и обновлений статуса."</string> <string name="people_tile_title" msgid="6589377493334871272">"Чат"</string> <string name="paused_by_dnd" msgid="7856941866433556428">"Приостановлено в режиме \"Не беспокоить\""</string> - <!-- no translation found for new_notification_text_content_description (2915029960094389291) --> - <skip /> + <string name="new_notification_text_content_description" msgid="2915029960094389291">"Пользователь <xliff:g id="NAME">%1$s</xliff:g> отправил сообщение: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"Пользователь <xliff:g id="NAME">%1$s</xliff:g> отправил изображение"</string> - <!-- no translation found for new_status_content_description (6046637888641308327) --> + <string name="new_status_content_description" msgid="6046637888641308327">"Пользователь <xliff:g id="NAME">%1$s</xliff:g> обновил статус: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <!-- no translation found for person_available (2318599327472755472) --> <skip /> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Не удается получить данные об уровне заряда батареи"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Нажмите, чтобы узнать больше."</string> diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml index 79eb6baf867d..4235d815d504 100644 --- a/packages/SystemUI/res/values-si/strings.xml +++ b/packages/SystemUI/res/values-si/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"මායිමට ගෙන යන්න සහ සඟවන්න"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"මායිමෙන් පිටට ගන්න සහ පෙන්වන්න"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"ටොගල් කරන්න"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"නිවෙස් පාලන"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"උපාංග පාලන"</string> <string name="controls_providers_title" msgid="6879775889857085056">"පාලන එක් කිරීමට යෙදුම තෝරා ගන්න"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="one">පාලන <xliff:g id="NUMBER_1">%s</xliff:g>ක් එක් කරන ලදී.</item> @@ -1149,6 +1149,7 @@ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> පණිවිඩයක් එවා ඇත: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> රූපයක් යවන ලදී"</string> <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> හට තත්ත්ව යාවත්කාලීනයක් ඇත: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <string name="person_available" msgid="2318599327472755472">"තිබේ"</string> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"ඔබගේ බැටරි මනුව කියවීමේ දෝෂයකි"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"තවත් තොරතුරු සඳහා තට්ටු කරන්න"</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"එලාම සකසා නැත"</string> diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml index ddf054adc8c6..4967718196ef 100644 --- a/packages/SystemUI/res/values-sk/strings.xml +++ b/packages/SystemUI/res/values-sk/strings.xml @@ -1054,7 +1054,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Presunúť k okraju a skryť"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Presunúť z okraja a zobraziť"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"prepínač"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"Ovládanie domácnosti"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Ovládanie zariadení"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Vyberte aplikáciu, ktorej ovládače si chcete pridať"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="few">Boli pridané <xliff:g id="NUMBER_1">%s</xliff:g> ovládacie prvky.</item> @@ -1158,10 +1158,10 @@ <string name="people_tile_description" msgid="8154966188085545556">"Pozrite si nedávne správy, zmeškané hovory a aktualizácie stavu"</string> <string name="people_tile_title" msgid="6589377493334871272">"Konverzácia"</string> <string name="paused_by_dnd" msgid="7856941866433556428">"Pozastavené režimom bez vyrušení"</string> - <!-- no translation found for new_notification_text_content_description (2915029960094389291) --> - <skip /> + <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> poslal(a) správu: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> poslal(a) obrázok"</string> - <!-- no translation found for new_status_content_description (6046637888641308327) --> + <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> má aktualizáciu statusu: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <!-- no translation found for person_available (2318599327472755472) --> <skip /> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Pri čítaní meradla batérie sa vyskytol problém"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Klepnutím si zobrazíte ďalšie informácie"</string> diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml index 1af9e029dd1f..a553ff225e18 100644 --- a/packages/SystemUI/res/values-sl/strings.xml +++ b/packages/SystemUI/res/values-sl/strings.xml @@ -1054,7 +1054,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Premakni na rob in skrij"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Premakni z roba in pokaži"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"preklop"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"Kontrolniki za dom"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Kontrolniki naprave"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Izberite aplikacijo za dodajanje kontrolnikov"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> kontrolnik dodan.</item> @@ -1161,6 +1161,7 @@ <string name="new_notification_text_content_description" msgid="2915029960094389291">"Oseba <xliff:g id="NAME">%1$s</xliff:g> je poslala sporočilo: <xliff:g id="NOTIFICATION">%2$s</xliff:g>."</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"Oseba <xliff:g id="NAME">%1$s</xliff:g> je poslala sliko."</string> <string name="new_status_content_description" msgid="6046637888641308327">"Oseba <xliff:g id="NAME">%1$s</xliff:g> je posodobila stanje: <xliff:g id="STATUS">%2$s</xliff:g>."</string> + <string name="person_available" msgid="2318599327472755472">"Na voljo"</string> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Težava z branjem indikatorja stanja napolnjenosti baterije"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Dotaknite se za več informacij"</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Ni nastavljenih alarmov"</string> diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml index 90cbdd1e18dc..ad8e2659b612 100644 --- a/packages/SystemUI/res/values-sq/strings.xml +++ b/packages/SystemUI/res/values-sq/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Zhvendose te skaji dhe fshihe"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Zhvendose jashtë skajit dhe shfaqe"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"aktivizo/çaktivizo"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"Kontrollet e shtëpisë"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Kontrollet e pajisjes"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Zgjidh aplikacionin për të shtuar kontrollet"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="other">U shtuan <xliff:g id="NUMBER_1">%s</xliff:g> kontrolle.</item> @@ -1146,10 +1146,10 @@ <string name="people_tile_description" msgid="8154966188085545556">"Shiko mesazhet e fundit, telefonatat e humbura dhe përditësimet e statusit"</string> <string name="people_tile_title" msgid="6589377493334871272">"Biseda"</string> <string name="paused_by_dnd" msgid="7856941866433556428">"Vendosur në pauzë nga \"Mos shqetëso\""</string> - <!-- no translation found for new_notification_text_content_description (2915029960094389291) --> - <skip /> + <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> dërgoi një mesazh: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> dërgoi një imazh"</string> - <!-- no translation found for new_status_content_description (6046637888641308327) --> + <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> ka një përditësim të statusit: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <!-- no translation found for person_available (2318599327472755472) --> <skip /> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problem me leximin e matësit të baterisë"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Trokit për më shumë informacione"</string> diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml index e9fbb78ccff3..282d18ba77e0 100644 --- a/packages/SystemUI/res/values-sr/strings.xml +++ b/packages/SystemUI/res/values-sr/strings.xml @@ -1049,7 +1049,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Премести до ивице и сакриј"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Премести изван ивице и прикажи"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"укључите/искључите"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"Контроле за дом"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Контроле уређаја"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Одаберите апликацију за додавање контрола"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> контрола је додата.</item> @@ -1155,6 +1155,7 @@ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> је послао/ла поруку: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> шаље слику"</string> <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> има ажурирање статуса: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <string name="person_available" msgid="2318599327472755472">"Доступно"</string> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Проблем са очитавањем мерача батерије"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Додирните за више информација"</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Аларм није подешен"</string> diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml index bcead0b250d3..c0588f666e39 100644 --- a/packages/SystemUI/res/values-sv/strings.xml +++ b/packages/SystemUI/res/values-sv/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Flytta till kanten och dölj"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Flytta från kanten och visa"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"aktivera och inaktivera"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"Hemstyrning"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Enhetsstyrning"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Välj en app om du vill lägga till snabbkontroller"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> kontroller har lagts till.</item> @@ -1149,6 +1149,8 @@ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> skickade ett meddelande: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> skickade en bild"</string> <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> har gjort en statusuppdatering: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <!-- no translation found for person_available (2318599327472755472) --> + <skip /> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Batteriindikatorn visas inte"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Tryck för mer information"</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Inget inställt alarm"</string> diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml index 8fa401a9fe44..e603fc94ecbc 100644 --- a/packages/SystemUI/res/values-sw/strings.xml +++ b/packages/SystemUI/res/values-sw/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Sogeza kwenye ukingo kisha ufiche"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Sogeza nje ya ukingo kisha uonyeshe"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"geuza"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"Udhibiti wa vifaa nyumbani"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Vidhibiti vya vifaa"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Chagua programu ili uweke vidhibiti"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="other">Umeweka vidhibiti <xliff:g id="NUMBER_1">%s</xliff:g>.</item> @@ -1149,6 +1149,7 @@ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> ametuma ujumbe: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ametuma picha"</string> <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> ana taarifa kuhusu hali: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <string name="person_available" msgid="2318599327472755472">"Anapatikana"</string> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Tatizo la kusoma mita ya betri yako"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Gusa ili upate maelezo zaidi"</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Hujaweka kengele"</string> diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml index 9c8ddca9c81d..d1d6d0d0c334 100644 --- a/packages/SystemUI/res/values-ta/strings.xml +++ b/packages/SystemUI/res/values-ta/strings.xml @@ -936,7 +936,7 @@ <string name="tuner_lock_screen" msgid="2267383813241144544">"லாக் ஸ்கிரீன்"</string> <string name="thermal_shutdown_title" msgid="2702966892682930264">"வெப்பத்தினால் ஃபோன் ஆஃப் செய்யப்பட்டது"</string> <string name="thermal_shutdown_message" msgid="6142269839066172984">"இப்போது உங்கள் மொபைல் இயல்புநிலையில் இயங்குகிறது.\nமேலும் தகவலுக்கு தட்டவும்"</string> - <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"உங்கள் ஃபோன் அதிகமாகச் சூடானதால், அதன் சூட்டைக் குறைக்க, ஆஃப் செய்யப்பட்டது. இப்போது உங்கள் ஃபோன் இயல்புநிலையில் இயங்குகிறது.\n\nபின்வருவனவற்றைச் செய்தால், ஃபோன் சூடாகலாம்:\n • அதிகளவு தரவைப் பயன்படுத்தும் ஆப்ஸை (எ.கா: கேமிங், வீடியோ (அ) வழிகாட்டுதல் ஆப்ஸ்) பயன்படுத்துவது\n • பெரிய கோப்புகளைப் பதிவிறக்குவது/பதிவேற்றுவது\n • அதிக வெப்பநிலையில் ஃபோனைப் பயன்படுத்துவது"</string> + <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"உங்கள் ஃபோன் அதிகமாகச் சூடானதால், அதன் சூட்டைக் குறைக்க, ஆஃப் செய்யப்பட்டது. இப்போது உங்கள் ஃபோன் இயல்புநிலையில் இயங்குகிறது.\n\nபின்வருவனவற்றைச் செய்தால், ஃபோன் சூடாகலாம்:\n • அதிகளவு தரவைப் பயன்படுத்தும் ஆப்ஸை (எ.கா: கேமிங், வீடியோ (அ) வழிகாட்டுதல் ஆப்ஸ்) பயன்படுத்துவது\n • பெரிய ஃபைல்களைப் பதிவிறக்குவது/பதிவேற்றுவது\n • அதிக வெப்பநிலையில் ஃபோனைப் பயன்படுத்துவது"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"மேலும் விவரங்களுக்கு இதைப் பார்க்கவும்"</string> <string name="high_temp_title" msgid="2218333576838496100">"மொபைல் சூடாகிறது"</string> <string name="high_temp_notif_message" msgid="1277346543068257549">"மொபைலின் வெப்ப அளவு குறையும் வரை சில அம்சங்களைப் பயன்படுத்த முடியாது.\nமேலும் தகவலுக்கு தட்டவும்"</string> @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"ஓரத்திற்கு நகர்த்தி மறை"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"ஓரத்திற்கு நகர்த்தி, காட்டு"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"நிலைமாற்று"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"முகப்புக் கட்டுப்பாடுகள்"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"சாதனக் கட்டுப்பாடுகள்"</string> <string name="controls_providers_title" msgid="6879775889857085056">"கட்டுப்பாடுகளைச் சேர்க்க வேண்டிய ஆப்ஸைத் தேர்ந்தெடுங்கள்"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> கட்டுப்பாடுகள் சேர்க்கப்பட்டன.</item> @@ -1146,11 +1146,10 @@ <string name="people_tile_description" msgid="8154966188085545556">"சமீபத்திய மெசேஜ்களையும் தவறிய அழைப்புகளையும் ஸ்டேட்டஸ் அப்டேட்களையும் பார்க்கலாம்"</string> <string name="people_tile_title" msgid="6589377493334871272">"உரையாடல்"</string> <string name="paused_by_dnd" msgid="7856941866433556428">"தொந்தரவு செய்ய வேண்டாம் அம்சத்தால் இடைநிறுத்தப்பட்டது"</string> - <!-- no translation found for new_notification_text_content_description (2915029960094389291) --> - <skip /> + <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> ஒரு மெசேஜ் அனுப்பியுள்ளார்: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ஒரு படம் அனுப்பியுள்ளார்"</string> - <!-- no translation found for new_status_content_description (6046637888641308327) --> - <skip /> + <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> புதிய ஸ்டேட்டஸ் வைத்துள்ளார்: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <string name="person_available" msgid="2318599327472755472">"ஆன்லைனில் இருக்கிறார்"</string> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"பேட்டரி அளவை அறிவதில் சிக்கல்"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"மேலும் தகவல்களுக்கு தட்டவும்"</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"அலாரம் எதுவுமில்லை"</string> diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml index d4375a57ad3b..409eced5a67d 100644 --- a/packages/SystemUI/res/values-te/strings.xml +++ b/packages/SystemUI/res/values-te/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"అంచుకు తరలించి దాచండి"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"అంచుని తరలించి చూపించు"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"టోగుల్ చేయి"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"హోమ్ కంట్రోల్స్"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"డివైజ్ కంట్రోల్స్"</string> <string name="controls_providers_title" msgid="6879775889857085056">"కంట్రోల్స్ను యాడ్ చేయడానికి యాప్ను ఎంచుకోండి"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> కంట్రోల్లు యాడ్ అయ్యాయి.</item> @@ -1146,10 +1146,10 @@ <string name="people_tile_description" msgid="8154966188085545556">"ఇటీవలి మెసేజ్లు, మిస్డ్ కాల్లు, అలాగే స్టేటస్ అప్డేట్లను చూడండి"</string> <string name="people_tile_title" msgid="6589377493334871272">"సంభాషణ"</string> <string name="paused_by_dnd" msgid="7856941866433556428">"అంతరాయం కలిగించవద్దు ద్వారా పాజ్ చేయబడింది"</string> - <!-- no translation found for new_notification_text_content_description (2915029960094389291) --> - <skip /> + <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> మెసేజ్ను పంపారు: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ఇమేజ్ను పంపారు"</string> - <!-- no translation found for new_status_content_description (6046637888641308327) --> + <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g>, స్టేటస్ను గురించిన అప్డేట్ను కలిగి ఉన్నారు: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <!-- no translation found for person_available (2318599327472755472) --> <skip /> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"మీ బ్యాటరీ మీటర్ను చదవడంలో సమస్య"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"మరింత సమాచారం కోసం ట్యాప్ చేయండి"</string> diff --git a/packages/SystemUI/res/values-television/dimens.xml b/packages/SystemUI/res/values-television/dimens.xml index c258fcc4273a..76c620d53ccf 100644 --- a/packages/SystemUI/res/values-television/dimens.xml +++ b/packages/SystemUI/res/values-television/dimens.xml @@ -38,7 +38,7 @@ <dimen name="bottom_sheet_min_height">208dp</dimen> <dimen name="bottom_sheet_margin">24dp</dimen> - <dimen name="bottom_sheet_background_blur_radius">120dp</dimen> + <dimen name="bottom_sheet_background_blur_radius">37dp</dimen> <dimen name="privacy_chip_margin">12dp</dimen> <dimen name="privacy_chip_icon_margin_in_between">9dp</dimen> @@ -56,4 +56,4 @@ <dimen name="privacy_chip_dot_bg_height">18dp</dimen> <dimen name="privacy_chip_dot_bg_radius">9dp</dimen> -</resources>
\ No newline at end of file +</resources> diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml index 6ecb2b491cc1..6e0662693d4a 100644 --- a/packages/SystemUI/res/values-th/strings.xml +++ b/packages/SystemUI/res/values-th/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"ย้ายไปที่ขอบและซ่อน"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"ย้ายออกจากขอบและแสดง"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"สลับ"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"ระบบควบคุมอุปกรณ์ในบ้าน"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"ระบบควบคุมอุปกรณ์"</string> <string name="controls_providers_title" msgid="6879775889857085056">"เลือกแอปเพื่อเพิ่มตัวควบคุม"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="other">เพิ่มตัวควบคุม <xliff:g id="NUMBER_1">%s</xliff:g> ตัวแล้ว</item> @@ -1149,6 +1149,8 @@ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> ส่งข้อความ: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ส่งรูปภาพ"</string> <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> มีการอัปเดตสถานะ: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <!-- no translation found for person_available (2318599327472755472) --> + <skip /> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"พบปัญหาในการอ่านเครื่องวัดแบตเตอรี่"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"แตะดูข้อมูลเพิ่มเติม"</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"ไม่มีการตั้งปลุก"</string> diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml index cf38fa20b705..9a83c227bf32 100644 --- a/packages/SystemUI/res/values-tl/strings.xml +++ b/packages/SystemUI/res/values-tl/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Ilipat sa sulok at itago"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Alisin sa sulok at ipakita"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"i-toggle"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"Mga Home control"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Mga kontrol ng device"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Pumili ng app para magdagdag ng mga kontrol"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> kontrol ang naidagdag.</item> @@ -1149,6 +1149,8 @@ <string name="new_notification_text_content_description" msgid="2915029960094389291">"Nagpadala si <xliff:g id="NAME">%1$s</xliff:g> ng mensahe: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"Nagpadala si <xliff:g id="NAME">%1$s</xliff:g> ng larawan"</string> <string name="new_status_content_description" msgid="6046637888641308327">"May update sa status si <xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <!-- no translation found for person_available (2318599327472755472) --> + <skip /> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Nagkaproblema sa pagbabasa ng iyong battery meter"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"I-tap para sa higit pang impormasyon"</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Walang alarm"</string> diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml index 7308785a9d83..ac6ecd09b8d7 100644 --- a/packages/SystemUI/res/values-tr/strings.xml +++ b/packages/SystemUI/res/values-tr/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Kenara taşıyıp gizle"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Kenarın dışına taşıyıp göster"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"değiştir"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"Ev kontrolleri"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Cihaz denetimleri"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Denetim eklemek için uygulama seçin"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> kontrol eklendi.</item> @@ -1149,6 +1149,8 @@ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> bir mesaj gönderdi: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> bir resim gönderdi"</string> <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g>, durumunu güncelledi: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <!-- no translation found for person_available (2318599327472755472) --> + <skip /> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Pil ölçeriniz okunurken sorun oluştu"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Daha fazla bilgi için dokunun"</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Alarm ayarlanmadı"</string> diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml index 3910d4b8bb61..2e9f24029341 100644 --- a/packages/SystemUI/res/values-uk/strings.xml +++ b/packages/SystemUI/res/values-uk/strings.xml @@ -676,7 +676,7 @@ <string name="wallet_app_button_label" msgid="7123784239111190992">"Показати все"</string> <string name="wallet_action_button_label_unlock" msgid="8663239748726774487">"Розблокувати, щоб сплатити"</string> <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"Додати картку"</string> - <string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Триває оновлення"</string> + <string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Оновлення"</string> <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Розблокувати, щоб використовувати"</string> <string name="wallet_error_generic" msgid="257704570182963611">"Не вдалось отримати ваші картки. Повторіть спробу пізніше."</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Параметри блокування екрана"</string> @@ -1054,7 +1054,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Перемістити до краю, приховати"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Перемістити від краю, показати"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"перемкнути"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"Автоматизація дому"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Керування пристроями"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Виберіть, для якого додатка налаштувати елементи керування"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="one">Додано <xliff:g id="NUMBER_1">%s</xliff:g> елемент керування.</item> @@ -1161,6 +1161,8 @@ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> надсилає повідомлення: \"<xliff:g id="NOTIFICATION">%2$s</xliff:g>\""</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> надсилає зображення"</string> <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> публікує новий статус: \"<xliff:g id="STATUS">%2$s</xliff:g>\""</string> + <!-- no translation found for person_available (2318599327472755472) --> + <skip /> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Не вдалось отримати дані лічильника акумулятора"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Натисніть, щоб дізнатися більше"</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Немає будильників"</string> diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml index 0612014b7e15..ffcd9a750abf 100644 --- a/packages/SystemUI/res/values-ur/strings.xml +++ b/packages/SystemUI/res/values-ur/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"EDGE پر لے جائیں اور چھپائیں"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"EDGE اور شو سے باہر منتقل کریں"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"ٹوگل کریں"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"ہوم کنٹرولز"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"آلہ کے کنٹرولز"</string> <string name="controls_providers_title" msgid="6879775889857085056">"کنٹرولز شامل کرنے کے لیے ایپ منتخب کریں"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> کنٹرولز شامل کر دیے گئے۔</item> @@ -1146,10 +1146,10 @@ <string name="people_tile_description" msgid="8154966188085545556">"حالیہ پیغامات، چھوٹی ہوئی کالز اور اسٹیٹس اپ ڈیٹس دیکھیں"</string> <string name="people_tile_title" msgid="6589377493334871272">"گفتگو"</string> <string name="paused_by_dnd" msgid="7856941866433556428">"\'ڈسٹرب نہ کریں\' کے ذریعے موقوف کیا گیا"</string> - <!-- no translation found for new_notification_text_content_description (2915029960094389291) --> - <skip /> + <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> نے ایک پیغام بھیجا: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> نے ایک تصویر بھیجی"</string> - <!-- no translation found for new_status_content_description (6046637888641308327) --> + <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> نے اسٹیٹس کو اپ ڈیٹ کر دیا ہے: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <!-- no translation found for person_available (2318599327472755472) --> <skip /> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"آپ کے بیٹری میٹر کو پڑھنے میں دشواری"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"مزید معلومات کے لیے تھپتھپائیں"</string> diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml index c5442564c0ba..b722acc87bef 100644 --- a/packages/SystemUI/res/values-uz/strings.xml +++ b/packages/SystemUI/res/values-uz/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Chetiga olib borish va yashirish"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Chetidan qaytarish va koʻrsatish"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"oʻzgartirish"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"Uy boshqaruvi"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Qurilmalarni boshqarish"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Boshqaruv elementlarini kiritish uchun ilovani tanlang"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> ta nazorat kiritilgan.</item> @@ -1149,6 +1149,7 @@ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> xabar yubordi: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> rasm yubordi"</string> <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> ahvolini yangiladi: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <string name="person_available" msgid="2318599327472755472">"Mavjud"</string> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Batareya quvvati aniqlanmadi"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Batafsil axborot olish uchun bosing"</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Signal sozlanmagan"</string> diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml index 3cf2b55cf44e..bc186362ad86 100644 --- a/packages/SystemUI/res/values-vi/strings.xml +++ b/packages/SystemUI/res/values-vi/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Chuyển đến cạnh và ẩn"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Chuyển ra xa cạnh và hiển thị"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"bật/tắt"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"Điều khiển nhà"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Điều khiển thiết bị"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Chọn ứng dụng để thêm các tùy chọn điều khiển"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="other">Đã thêm <xliff:g id="NUMBER_1">%s</xliff:g> tùy chọn điều khiển.</item> @@ -1146,10 +1146,10 @@ <string name="people_tile_description" msgid="8154966188085545556">"Xem các tin nhắn, cuộc gọi nhỡ và thông tin cập nhật trạng thái gần đây"</string> <string name="people_tile_title" msgid="6589377493334871272">"Cuộc trò chuyện"</string> <string name="paused_by_dnd" msgid="7856941866433556428">"Đã tạm dừng do chế độ Không làm phiền"</string> - <!-- no translation found for new_notification_text_content_description (2915029960094389291) --> - <skip /> + <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> đã gửi một tin nhắn: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> đã gửi một hình ảnh"</string> - <!-- no translation found for new_status_content_description (6046637888641308327) --> + <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> đã cập nhật trạng thái: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <!-- no translation found for person_available (2318599327472755472) --> <skip /> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Đã xảy ra vấn đề khi đọc dung lượng pin của bạn"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Nhấn để biết thêm thông tin"</string> diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml index 7cb429b49906..ae118bc22ead 100644 --- a/packages/SystemUI/res/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res/values-zh-rCN/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"移至边缘并隐藏"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"移至边缘以外并显示"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"开启/关闭"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"家居控制"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"设备控制器"</string> <string name="controls_providers_title" msgid="6879775889857085056">"选择要添加控制器的应用"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="other">已添加 <xliff:g id="NUMBER_1">%s</xliff:g> 个控件。</item> @@ -1146,10 +1146,10 @@ <string name="people_tile_description" msgid="8154966188085545556">"查看近期的消息、未接电话和状态更新"</string> <string name="people_tile_title" msgid="6589377493334871272">"对话"</string> <string name="paused_by_dnd" msgid="7856941866433556428">"勿扰模式已暂停通知"</string> - <!-- no translation found for new_notification_text_content_description (2915029960094389291) --> - <skip /> + <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g>发送了一条消息:<xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g>发送了一张图片"</string> - <!-- no translation found for new_status_content_description (6046637888641308327) --> + <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g>更新了状态:<xliff:g id="STATUS">%2$s</xliff:g>"</string> + <!-- no translation found for person_available (2318599327472755472) --> <skip /> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"读取电池计量器时出现问题"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"点按即可了解详情"</string> diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml index 641c9b738d7c..ea9f1fc1d472 100644 --- a/packages/SystemUI/res/values-zh-rHK/strings.xml +++ b/packages/SystemUI/res/values-zh-rHK/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"移到邊緣並隱藏"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"從邊緣移出並顯示"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"切換"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"智能家居"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"裝置控制"</string> <string name="controls_providers_title" msgid="6879775889857085056">"選擇要新增控制項的應用程式"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="other">已新增 <xliff:g id="NUMBER_1">%s</xliff:g> 個控制項。</item> @@ -1149,6 +1149,7 @@ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g>傳送了訊息:<xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g>傳送了圖片"</string> <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g>有狀態更新:<xliff:g id="STATUS">%2$s</xliff:g>"</string> + <string name="person_available" msgid="2318599327472755472">"有空"</string> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"讀取電池計量器時發生問題"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"輕按即可瞭解詳情"</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"未設定鬧鐘"</string> diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml index 787e7b09ebed..98b90cc13457 100644 --- a/packages/SystemUI/res/values-zh-rTW/strings.xml +++ b/packages/SystemUI/res/values-zh-rTW/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"移到邊緣並隱藏"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"從邊緣移出並顯示"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"切換"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"居家控制系統"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"裝置控制"</string> <string name="controls_providers_title" msgid="6879775889857085056">"選擇應用程式以新增控制項"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="other">已新增 <xliff:g id="NUMBER_1">%s</xliff:g> 個控制項。</item> @@ -1146,10 +1146,10 @@ <string name="people_tile_description" msgid="8154966188085545556">"查看最近的訊息、未接來電和狀態更新"</string> <string name="people_tile_title" msgid="6589377493334871272">"對話"</string> <string name="paused_by_dnd" msgid="7856941866433556428">"零打擾模式已將通知暫停"</string> - <!-- no translation found for new_notification_text_content_description (2915029960094389291) --> - <skip /> + <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g>傳送了一則訊息:<xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g>傳送了一張圖片"</string> - <!-- no translation found for new_status_content_description (6046637888641308327) --> + <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g>更新了狀態:<xliff:g id="STATUS">%2$s</xliff:g>"</string> + <!-- no translation found for person_available (2318599327472755472) --> <skip /> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"讀取電池計量器時發生問題"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"輕觸即可瞭解詳情"</string> diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml index 883c7466505c..6ced59776adf 100644 --- a/packages/SystemUI/res/values-zu/strings.xml +++ b/packages/SystemUI/res/values-zu/strings.xml @@ -1044,7 +1044,7 @@ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Hamba onqenqemeni ufihle"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Phuma onqenqemeni ubonise"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"guqula"</string> - <string name="quick_controls_title" msgid="7095074621086860062">"Izilawuli zasekhaya"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Izilawuli zezinsiza"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Khetha uhlelo lokusebenza ukwengeza izilawuli"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> ukulawulwa okwengeziwe.</item> @@ -1149,6 +1149,8 @@ <string name="new_notification_text_content_description" msgid="2915029960094389291">"U-<xliff:g id="NAME">%1$s</xliff:g> uthumele umlayezo: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> <string name="new_notification_image_content_description" msgid="6017506886810813123">"U-<xliff:g id="NAME">%1$s</xliff:g> uthumele isithombe"</string> <string name="new_status_content_description" msgid="6046637888641308327">"U-<xliff:g id="NAME">%1$s</xliff:g> unesibuyekezo sesimo: <xliff:g id="STATUS">%2$s</xliff:g>"</string> + <!-- no translation found for person_available (2318599327472755472) --> + <skip /> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Kube khona inkinga ngokufunda imitha yakho yebhethri"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Thepha ukuze uthole olunye ulwazi"</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Akukho alamu esethiwe"</string> diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 478bf9aa6afb..d72286628c37 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -442,9 +442,6 @@ vibrator is capable of subtle vibrations --> <bool name="config_vibrateOnIconAnimation">false</bool> - <!-- Adjust the theme on fully custom and decorated custom view notifications --> - <bool name="config_adjustThemeOnNotificationCustomViews">false</bool> - <!-- Notifications are sized to match the width of two (of 4) qs tiles in landscape. --> <bool name="config_skinnyNotifsInLandscape">true</bool> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 734c1198a346..5fec796669aa 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -62,7 +62,9 @@ <item name="navigation_luminance_change_threshold" type="dimen" format="float">0.05</item> <dimen name="floating_rotation_button_diameter">40dp</dimen> - <dimen name="floating_rotation_button_min_margin">4dp</dimen> + <dimen name="floating_rotation_button_min_margin">20dp</dimen> + <dimen name="floating_rotation_button_taskbar_left_margin">20dp</dimen> + <dimen name="floating_rotation_button_taskbar_bottom_margin">10dp</dimen> <!-- Height of notification icons in the status bar --> <dimen name="status_bar_icon_size">@*android:dimen/status_bar_icon_size</dimen> @@ -689,6 +691,9 @@ <!-- The height of the divider between the individual notifications. --> <dimen name="notification_divider_height">2dp</dimen> + <!-- The min distance the notifications should be from the lock icon on the lock screen. --> + <dimen name="min_lock_icon_padding">48dp</dimen> + <!-- The corner radius of the shadow behind the notification. --> <dimen name="notification_shadow_radius">0dp</dimen> @@ -1250,7 +1255,7 @@ <!-- Blur radius on status bar window and power menu --> <dimen name="min_window_blur_radius">1px</dimen> - <dimen name="max_window_blur_radius">72px</dimen> + <dimen name="max_window_blur_radius">23px</dimen> <!-- How much into a DisplayCutout's bounds we can go, on each side --> <dimen name="display_cutout_margin_consumption">0px</dimen> @@ -1484,6 +1489,8 @@ <dimen name="content_text_size_for_large">14sp</dimen> <dimen name="below_name_text_padding">16dp</dimen> <dimen name="above_notification_text_padding">22dp</dimen> + <dimen name="before_messages_count_padding">40dp</dimen> + <dimen name="before_predefined_icon_padding">30dp</dimen> <dimen name="regular_predefined_icon">18dp</dimen> <dimen name="larger_predefined_icon">24dp</dimen> <dimen name="largest_predefined_icon">32dp</dimen> diff --git a/packages/SystemUI/res/values/dimens_tv.xml b/packages/SystemUI/res/values/dimens_tv.xml index 5bd95ebc1c41..3dbd9903b62e 100644 --- a/packages/SystemUI/res/values/dimens_tv.xml +++ b/packages/SystemUI/res/values/dimens_tv.xml @@ -16,5 +16,5 @@ --> <resources> <dimen name="tv_notification_panel_width">360dp</dimen> - <dimen name="tv_notification_blur_radius">100dp</dimen> -</resources>
\ No newline at end of file + <dimen name="tv_notification_blur_radius">31dp</dimen> +</resources> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index dd9a6c177b14..5796c19b15e6 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -2728,7 +2728,7 @@ <!-- Device Controls strings --> <!-- Device Controls, Quick Settings tile title [CHAR LIMIT=30] --> - <string name="quick_controls_title">Home controls</string> + <string name="quick_controls_title">Device controls</string> <!-- Controls management providers screen title [CHAR LIMIT=60]--> <string name="controls_providers_title">Choose app to add controls</string> @@ -2956,6 +2956,8 @@ <string name="new_notification_image_content_description"><xliff:g id="name" example="Anna">%1$s</xliff:g> sent an image</string> <!-- Content description text on the Conversation widget when a person has a new status posted [CHAR LIMIT=150] --> <string name="new_status_content_description"><xliff:g id="name" example="Anna">%1$s</xliff:g> has a status update: <xliff:g id="status" example="Listening to music">%2$s</xliff:g></string> + <!-- Content description text on the Conversation widget when a person is available, meaning online on an application [CHAR LIMIT=150] --> + <string name="person_available">Available</string> <!-- Title to display in a notification when ACTION_BATTERY_CHANGED.EXTRA_PRESENT field is false [CHAR LIMIT=NONE] --> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index 17a984e48ff1..70ed81788e58 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -777,6 +777,7 @@ <style name="Theme.PeopleTileConfigActivity" parent="@style/Theme.SystemUI"> <item name="android:windowActionBar">false</item> <item name="android:windowNoTitle">true</item> + <item name="android:windowLightStatusBar">true</item> </style> <style name="TextAppearance.Control"> diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl index f72245b9b252..11557ad87929 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl @@ -140,5 +140,8 @@ interface ISystemUiProxy { /** Notifies that a swipe-up gesture has started */ oneway void notifySwipeUpGestureStarted() = 46; - // Next id = 47 + /** Notifies when taskbar status updated */ + oneway void notifyTaskbarStatus(boolean visible, boolean stashed) = 47; + + // Next id = 48 } diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java index a624f06110e6..e33985dc4288 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java @@ -19,15 +19,21 @@ package com.android.systemui.shared.recents.utilities; import static android.app.StatusBarManager.NAVIGATION_HINT_BACK_ALT; import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SHOWN; +import android.content.Context; +import android.content.res.Configuration; +import android.content.res.Resources; import android.graphics.Color; import android.inputmethodservice.InputMethodService; import android.os.Handler; import android.os.Message; +import android.util.DisplayMetrics; import android.view.Surface; /* Common code */ public class Utilities { + private static final float TABLET_MIN_DPS = 600; + /** * Posts a runnable on a handler at the front of the queue ignoring any sync barriers. */ @@ -110,4 +116,22 @@ public class Utilities { return hints; } + + /** See {@link #isTablet(Configuration, Context)} */ + public static boolean isTablet(Context context) { + Configuration newConfig = context.getResources().getConfiguration(); + return isTablet(newConfig, context); + } + + /** + * @return whether or not {@param newConfig} represents that of a large screen device or not + */ + public static boolean isTablet(Configuration newConfig, Context context) { + float density = Resources.getSystem().getDisplayMetrics().density; + int size = Math.min((int) (density * newConfig.screenWidthDp), + (int) (density* newConfig.screenHeightDp)); + DisplayMetrics metrics = context.getResources().getDisplayMetrics(); + float densityRatio = (float) metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT; + return (size / densityRatio) >= TABLET_MIN_DPS; + } } diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java index fdd1abebe0ea..025d7ef48096 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java @@ -69,7 +69,8 @@ public class RemoteAnimationAdapterCompat { return mRemoteTransition; } - private static IRemoteAnimationRunner.Stub wrapRemoteAnimationRunner( + /** Wraps a RemoteAnimationRunnerCompat in an IRemoteAnimationRunner. */ + public static IRemoteAnimationRunner.Stub wrapRemoteAnimationRunner( final RemoteAnimationRunnerCompat remoteAnimationAdapter) { return new IRemoteAnimationRunner.Stub() { @Override diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java index a77cc87a4e2c..3eea99a46245 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java @@ -27,6 +27,7 @@ import static android.window.TransitionFilter.CONTAINER_ORDER_TOP; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SuppressLint; +import android.app.ActivityManager; import android.app.ActivityTaskManager; import android.graphics.Rect; import android.os.IBinder; @@ -122,15 +123,20 @@ public class RemoteTransitionCompat implements Parcelable { // This transition is for opening recents, so recents is on-top. We want to draw // the current going-away task on top of recents, though, so move it to front WindowContainerToken pausingTask = null; - SurfaceControl pausingLeash = null; + WindowContainerToken pipTask = null; for (int i = info.getChanges().size() - 1; i >= 0; --i) { final TransitionInfo.Change change = info.getChanges().get(i); if (change.getMode() == TRANSIT_CLOSE || change.getMode() == TRANSIT_TO_BACK) { t.setLayer(leashMap.get(change.getLeash()), info.getChanges().size() * 3 - i); - if (change.getTaskInfo() != null) { + final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo(); + if (taskInfo != null) { pausingTask = change.getTaskInfo().token; } + if (taskInfo.pictureInPictureParams != null + && taskInfo.pictureInPictureParams.isAutoEnterEnabled()) { + pipTask = change.getTaskInfo().token; + } } } // Also make all the wallpapers opaque since we want the visible from the start @@ -138,7 +144,7 @@ public class RemoteTransitionCompat implements Parcelable { t.setAlpha(wallpapers[i].leash.mSurfaceControl, 1); } t.apply(); - mRecentsSession.setup(controller, info, finishedCallback, pausingTask, + mRecentsSession.setup(controller, info, finishedCallback, pausingTask, pipTask, leashMap, mToken); recents.onAnimationStart(mRecentsSession, apps, wallpapers, new Rect(0, 0, 0, 0), new Rect()); @@ -183,14 +189,17 @@ public class RemoteTransitionCompat implements Parcelable { private RecentsAnimationControllerCompat mWrapped = null; private IRemoteTransitionFinishedCallback mFinishCB = null; private WindowContainerToken mPausingTask = null; + private WindowContainerToken mPipTask = null; private TransitionInfo mInfo = null; private SurfaceControl mOpeningLeash = null; private ArrayMap<SurfaceControl, SurfaceControl> mLeashMap = null; + private PictureInPictureSurfaceTransaction mPipTransaction = null; private IBinder mTransition = null; void setup(RecentsAnimationControllerCompat wrapped, TransitionInfo info, IRemoteTransitionFinishedCallback finishCB, WindowContainerToken pausingTask, - ArrayMap<SurfaceControl, SurfaceControl> leashMap, IBinder transition) { + WindowContainerToken pipTask, ArrayMap<SurfaceControl, SurfaceControl> leashMap, + IBinder transition) { if (mInfo != null) { throw new IllegalStateException("Trying to run a new recents animation while" + " recents is already active."); @@ -199,6 +208,7 @@ public class RemoteTransitionCompat implements Parcelable { mInfo = info; mFinishCB = finishCB; mPausingTask = pausingTask; + mPipTask = pipTask; mLeashMap = leashMap; mTransition = transition; } @@ -257,6 +267,7 @@ public class RemoteTransitionCompat implements Parcelable { @Override public void setFinishTaskTransaction(int taskId, PictureInPictureSurfaceTransaction finishTransaction, SurfaceControl overlay) { + mPipTransaction = finishTransaction; if (mWrapped != null) { mWrapped.setFinishTaskTransaction(taskId, finishTransaction, overlay); } @@ -288,7 +299,18 @@ public class RemoteTransitionCompat implements Parcelable { t.setAlpha(mOpeningLeash, 1.f); t.apply(); } - mFinishCB.onTransitionFinished(null /* wct */, null /* sct */); + if (mPipTask != null && mPipTransaction != null) { + final SurfaceControl.Transaction t = new SurfaceControl.Transaction(); + t.show(mInfo.getChange(mPipTask).getLeash()); + PictureInPictureSurfaceTransaction.apply(mPipTransaction, + mInfo.getChange(mPipTask).getLeash(), t); + mPipTask = null; + mPipTransaction = null; + mFinishCB.onTransitionFinished(null /* wct */, t); + } else { + mFinishCB.onTransitionFinished(null /* wct */, null /* sct */); + } + } } catch (RemoteException e) { Log.e("RemoteTransitionCompat", "Failed to call animation finish callback", e); diff --git a/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java b/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java index 4b3af34b1df1..c89cda98c8a5 100644 --- a/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java +++ b/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java @@ -21,7 +21,6 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.graphics.Color; -import android.hardware.biometrics.BiometricSourceType; import android.icu.text.NumberFormat; import com.android.settingslib.Utils; @@ -94,9 +93,7 @@ public class AnimatableClockController extends ViewController<AnimatableClockVie @Override public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) { if (mKeyguardShowing && !mIsCharging && charging) { - mView.animateCharge(() -> { - return mStatusBarStateController.isDozing(); - }); + mView.animateCharge(mStatusBarStateController::isDozing); } mIsCharging = charging; } @@ -127,21 +124,10 @@ public class AnimatableClockController extends ViewController<AnimatableClockVie private final KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback = new KeyguardUpdateMonitorCallback() { @Override - public void onBiometricAuthenticated(int userId, BiometricSourceType biometricSourceType, - boolean isStrongBiometric) { - // Strong auth will force the bouncer regardless of a successful face auth - if (biometricSourceType == BiometricSourceType.FACE - && mBypassController.canBypass() - && !mKeyguardUpdateMonitor.userNeedsStrongAuth()) { - mView.animateDisappear(); - } - } - - @Override public void onKeyguardVisibilityChanged(boolean showing) { mKeyguardShowing = showing; if (!mKeyguardShowing) { - // reset state (ie: after animateDisappear) + // reset state (ie: after weight animations) reset(); } } @@ -156,7 +142,6 @@ public class AnimatableClockController extends ViewController<AnimatableClockVie mDozeAmount = mStatusBarStateController.getDozeAmount(); mBatteryController.addCallback(mBatteryCallback); mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback); - mKeyguardShowing = true; mStatusBarStateController.removeCallback(mStatusBarStatePersistentListener); mStatusBarStateController.addCallback(mStatusBarStatePersistentListener); @@ -212,6 +197,7 @@ public class AnimatableClockController extends ViewController<AnimatableClockVie } else { mView.setLineSpacingScale(mDefaultLineSpacing); } + mView.refreshFormat(); } } diff --git a/packages/SystemUI/src/com/android/keyguard/AnimatableClockView.java b/packages/SystemUI/src/com/android/keyguard/AnimatableClockView.java index 58b3865facbc..ef3104a21708 100644 --- a/packages/SystemUI/src/com/android/keyguard/AnimatableClockView.java +++ b/packages/SystemUI/src/com/android/keyguard/AnimatableClockView.java @@ -19,9 +19,9 @@ package com.android.keyguard; import android.annotation.FloatRange; import android.annotation.IntRange; import android.content.Context; +import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Canvas; -import android.icu.text.DateTimePatternGenerator; import android.text.format.DateFormat; import android.util.AttributeSet; import android.widget.TextView; @@ -30,6 +30,7 @@ import com.android.systemui.R; import com.android.systemui.statusbar.phone.KeyguardBypassController; import java.util.Calendar; +import java.util.Locale; import java.util.TimeZone; import kotlin.Unit; @@ -41,8 +42,6 @@ import kotlin.Unit; public class AnimatableClockView extends TextView { private static final CharSequence DOUBLE_LINE_FORMAT_12_HOUR = "hh\nmm"; private static final CharSequence DOUBLE_LINE_FORMAT_24_HOUR = "HH\nmm"; - private static final CharSequence SINGLE_LINE_FORMAT_12_HOUR = "h:mm"; - private static final CharSequence SINGLE_LINE_FORMAT_24_HOUR = "HH:mm"; private static final long DOZE_ANIM_DURATION = 300; private static final long APPEAR_ANIM_DURATION = 350; private static final long CHARGE_ANIM_DURATION_PHASE_0 = 500; @@ -259,25 +258,47 @@ public class AnimatableClockView extends TextView { } void refreshFormat() { + Patterns.update(mContext); + final boolean use24HourFormat = DateFormat.is24HourFormat(getContext()); if (mIsSingleLine && use24HourFormat) { - mFormat = SINGLE_LINE_FORMAT_24_HOUR; + mFormat = Patterns.sClockView24; } else if (!mIsSingleLine && use24HourFormat) { mFormat = DOUBLE_LINE_FORMAT_24_HOUR; } else if (mIsSingleLine && !use24HourFormat) { - mFormat = SINGLE_LINE_FORMAT_12_HOUR; + mFormat = Patterns.sClockView12; } else { mFormat = DOUBLE_LINE_FORMAT_12_HOUR; } - mDescFormat = getBestDateTimePattern(getContext(), use24HourFormat ? "Hm" : "hm"); + mDescFormat = use24HourFormat ? Patterns.sClockView24 : Patterns.sClockView12; refreshTime(); } - private static String getBestDateTimePattern(Context context, String skeleton) { - DateTimePatternGenerator dtpg = DateTimePatternGenerator.getInstance( - context.getResources().getConfiguration().locale); - return dtpg.getBestPattern(skeleton); + // DateFormat.getBestDateTimePattern is extremely expensive, and refresh is called often. + // This is an optimization to ensure we only recompute the patterns when the inputs change. + private static final class Patterns { + static String sClockView12; + static String sClockView24; + static String sCacheKey; + + static void update(Context context) { + final Locale locale = Locale.getDefault(); + final Resources res = context.getResources(); + final String clockView12Skel = res.getString(R.string.clock_12hr_format); + final String clockView24Skel = res.getString(R.string.clock_24hr_format); + final String key = locale.toString() + clockView12Skel + clockView24Skel; + if (key.equals(sCacheKey)) return; + sClockView12 = DateFormat.getBestDateTimePattern(locale, clockView12Skel); + + // CLDR insists on adding an AM/PM indicator even though it wasn't in the skeleton + // format. The following code removes the AM/PM indicator if we didn't want it. + if (!clockView12Skel.contains("a")) { + sClockView12 = sClockView12.replaceAll("a", "").trim(); + } + sClockView24 = DateFormat.getBestDateTimePattern(locale, clockView24Skel); + sCacheKey = key; + } } interface DozeStateGetter { diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java index e312c71718d5..9e456cf55500 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java @@ -22,9 +22,7 @@ import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; import static com.android.keyguard.KeyguardClockSwitch.LARGE; import android.app.WallpaperManager; -import android.content.res.Resources; import android.text.TextUtils; -import android.text.format.DateFormat; import android.view.View; import android.widget.FrameLayout; import android.widget.RelativeLayout; @@ -371,37 +369,6 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS return mColorExtractor.getColors(WallpaperManager.FLAG_LOCK); } - // DateFormat.getBestDateTimePattern is extremely expensive, and refresh is called often. - // This is an optimization to ensure we only recompute the patterns when the inputs change. - private static final class Patterns { - static String sClockView12; - static String sClockView24; - static String sCacheKey; - - static void update(Resources res) { - final Locale locale = Locale.getDefault(); - final String clockView12Skel = res.getString(R.string.clock_12hr_format); - final String clockView24Skel = res.getString(R.string.clock_24hr_format); - final String key = locale.toString() + clockView12Skel + clockView24Skel; - if (key.equals(sCacheKey)) return; - - sClockView12 = DateFormat.getBestDateTimePattern(locale, clockView12Skel); - // CLDR insists on adding an AM/PM indicator even though it wasn't in the skeleton - // format. The following code removes the AM/PM indicator if we didn't want it. - if (!clockView12Skel.contains("a")) { - sClockView12 = sClockView12.replaceAll("a", "").trim(); - } - - sClockView24 = DateFormat.getBestDateTimePattern(locale, clockView24Skel); - - // Use fancy colon. - sClockView24 = sClockView24.replace(':', '\uee01'); - sClockView12 = sClockView12.replace(':', '\uee01'); - - sCacheKey = key; - } - } - private int getCurrentLayoutDirection() { return TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()); } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java index 568bea0e2d24..62411dbff5fd 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java @@ -54,6 +54,7 @@ public class KeyguardMessageArea extends TextView implements SecurityMessageDisp private CharSequence mMessage; private ColorStateList mNextMessageColorState = ColorStateList.valueOf(DEFAULT_COLOR); private boolean mBouncerVisible; + private boolean mAltBouncerShowing; public KeyguardMessageArea(Context context, AttributeSet attrs) { super(context, attrs); @@ -144,7 +145,8 @@ public class KeyguardMessageArea extends TextView implements SecurityMessageDisp void update() { CharSequence status = mMessage; - setVisibility(TextUtils.isEmpty(status) || !mBouncerVisible ? INVISIBLE : VISIBLE); + setVisibility(TextUtils.isEmpty(status) || (!mBouncerVisible && !mAltBouncerShowing) + ? INVISIBLE : VISIBLE); setText(status); ColorStateList colorState = mDefaultColorState; if (mNextMessageColorState.getDefaultColor() != DEFAULT_COLOR) { @@ -159,6 +161,16 @@ public class KeyguardMessageArea extends TextView implements SecurityMessageDisp } /** + * Set whether the alt bouncer is showing + */ + void setAltBouncerShowing(boolean showing) { + if (mAltBouncerShowing != showing) { + mAltBouncerShowing = showing; + update(); + } + } + + /** * Runnable used to delay accessibility announcements. */ private static class AnnounceRunnable implements Runnable { diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java index 6e40f025da50..51ded3fcafdf 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java @@ -28,7 +28,7 @@ import javax.inject.Inject; public class KeyguardMessageAreaController extends ViewController<KeyguardMessageArea> { private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; private final ConfigurationController mConfigurationController; - + private boolean mAltBouncerShowing; private KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() { public void onFinishedGoingToSleep(int why) { @@ -81,6 +81,13 @@ public class KeyguardMessageAreaController extends ViewController<KeyguardMessag mKeyguardUpdateMonitor.removeCallback(mInfoCallback); } + /** + * Set whether alt bouncer is showing + */ + public void setAltBouncerShowing(boolean showing) { + mView.setAltBouncerShowing(showing); + } + public void setMessage(CharSequence s) { mView.setMessage(s); } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java index 215840142f42..8bf8e0926095 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java @@ -80,18 +80,6 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV dozeParameters, unlockedScreenOffAnimationController, /* animateYPos= */ true); mKeyguardUnlockAnimationController = keyguardUnlockAnimationController; mSmartspaceTransitionController = smartspaceTransitionController; - - mKeyguardStateController.addCallback(new KeyguardStateController.Callback() { - @Override - public void onKeyguardShowingChanged() { - // If we explicitly re-show the keyguard, make sure that all the child views are - // visible. They might have been animating out as part of the SmartSpace shared - // element transition. - if (keyguardStateController.isShowing()) { - mView.setChildrenAlphaExcludingClockView(1f); - } - } - }); } @Override @@ -103,12 +91,14 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV protected void onViewAttached() { mKeyguardUpdateMonitor.registerCallback(mInfoCallback); mConfigurationController.addCallback(mConfigurationListener); + mKeyguardStateController.addCallback(mKeyguardStateControllerCallback); } @Override protected void onViewDetached() { mKeyguardUpdateMonitor.removeCallback(mInfoCallback); mConfigurationController.removeCallback(mConfigurationListener); + mKeyguardStateController.removeCallback(mKeyguardStateControllerCallback); } /** @@ -278,6 +268,19 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV } }; + private KeyguardStateController.Callback mKeyguardStateControllerCallback = + new KeyguardStateController.Callback() { + @Override + public void onKeyguardShowingChanged() { + // If we explicitly re-show the keyguard, make sure that all the child views are + // visible. They might have been animating out as part of the SmartSpace shared + // element transition. + if (mKeyguardStateController.isShowing()) { + mView.setChildrenAlphaExcludingClockView(1f); + } + } + }; + /** * Rect that specifies how KSV should be clipped, on its parent's coordinates. */ diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconView.java b/packages/SystemUI/src/com/android/keyguard/LockIconView.java index c425ddf7eeb1..c1d448db1e63 100644 --- a/packages/SystemUI/src/com/android/keyguard/LockIconView.java +++ b/packages/SystemUI/src/com/android/keyguard/LockIconView.java @@ -43,7 +43,7 @@ public class LockIconView extends ImageView implements Dumpable { mSensorRect = new RectF(); } - void setLocation(@NonNull PointF center, int radius) { + void setCenterLocation(@NonNull PointF center, int radius) { mLockIconCenter = center; mRadius = radius; diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java index f3fbc50f560d..afea27222fbb 100644 --- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java @@ -24,8 +24,8 @@ import android.content.Context; import android.content.res.Configuration; import android.graphics.PointF; import android.graphics.Rect; +import android.graphics.drawable.AnimatedVectorDrawable; import android.graphics.drawable.Drawable; -import android.graphics.drawable.InsetDrawable; import android.hardware.biometrics.BiometricSourceType; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.util.DisplayMetrics; @@ -79,7 +79,8 @@ public class LockIconViewController extends ViewController<LockIconView> impleme @NonNull private final DelayableExecutor mExecutor; private boolean mUdfpsEnrolled; - @NonNull private final Drawable mUnlockIcon; + @NonNull private final AnimatedVectorDrawable mFpToUnlockIcon; + @NonNull private final AnimatedVectorDrawable mLockToUnlockIcon; @NonNull private final Drawable mLockIcon; @NonNull private final CharSequence mUnlockedLabel; @NonNull private final CharSequence mLockedLabel; @@ -98,7 +99,8 @@ public class LockIconViewController extends ViewController<LockIconView> impleme private float mHeightPixels; private float mWidthPixels; private float mDensity; - private int mIndicationBottomPadding; + private int mAmbientIndicationHeight; // in pixels + private int mKgIndicationHeight; // in pixels private boolean mShowUnlockIcon; private boolean mShowLockIcon; @@ -132,14 +134,14 @@ public class LockIconViewController extends ViewController<LockIconView> impleme mExecutor = executor; final Context context = view.getContext(); - mUnlockIcon = new InsetDrawable(context.getResources().getDrawable( - com.android.internal.R.drawable.ic_lock_open, context.getTheme()), - context.getResources().getDimensionPixelSize( - com.android.systemui.R.dimen.udfps_unlock_icon_inset)); - mLockIcon = new InsetDrawable(context.getResources().getDrawable( - com.android.internal.R.drawable.ic_lock, context.getTheme()), - context.getResources().getDimensionPixelSize( - com.android.systemui.R.dimen.udfps_unlock_icon_inset)); + mLockIcon = mView.getContext().getResources().getDrawable( + R.anim.lock_to_unlock, + mView.getContext().getTheme()); + mFpToUnlockIcon = (AnimatedVectorDrawable) mView.getContext().getResources().getDrawable( + R.anim.fp_to_unlock, mView.getContext().getTheme()); + mLockToUnlockIcon = (AnimatedVectorDrawable) mView.getContext().getResources().getDrawable( + R.anim.lock_to_unlock, + mView.getContext().getTheme()); mUnlockedLabel = context.getResources().getString(R.string.accessibility_unlock_button); mLockedLabel = context.getResources().getString(R.string.accessibility_lock_icon); dumpManager.registerDumpable("LockIconViewController", this); @@ -211,6 +213,8 @@ public class LockIconViewController extends ViewController<LockIconView> impleme return; } + boolean wasShowingFpIcon = mHasUdfps && !mShowUnlockIcon && !mShowLockIcon; + boolean wasShowingLockIcon = mShowLockIcon; mShowLockIcon = !mCanDismissLockScreen && !mUserUnlockedWithBiometric && isLockScreen() && (!mUdfpsEnrolled || !mRunningFPS); mShowUnlockIcon = mCanDismissLockScreen && isLockScreen(); @@ -221,7 +225,15 @@ public class LockIconViewController extends ViewController<LockIconView> impleme mView.setVisibility(View.VISIBLE); mView.setContentDescription(mLockedLabel); } else if (mShowUnlockIcon) { - mView.setImageDrawable(mUnlockIcon); + if (wasShowingFpIcon) { + mView.setImageDrawable(mFpToUnlockIcon); + mFpToUnlockIcon.forceAnimationOnUI(); + mFpToUnlockIcon.start(); + } else if (wasShowingLockIcon) { + mView.setImageDrawable(mLockToUnlockIcon); + mLockToUnlockIcon.forceAnimationOnUI(); + mLockToUnlockIcon.start(); + } mView.setVisibility(View.VISIBLE); mView.setContentDescription(mUnlockedLabel); } else { @@ -271,7 +283,8 @@ public class LockIconViewController extends ViewController<LockIconView> impleme private void updateColors() { final int color = Utils.getColorAttrDefaultColor(mView.getContext(), R.attr.wallpaperTextColorAccent); - mUnlockIcon.setTint(color); + mFpToUnlockIcon.setTint(color); + mLockToUnlockIcon.setTint(color); mLockIcon.setTint(color); } @@ -280,7 +293,9 @@ public class LockIconViewController extends ViewController<LockIconView> impleme mWidthPixels = metrics.widthPixels; mHeightPixels = metrics.heightPixels; mDensity = metrics.density; - mIndicationBottomPadding = mView.getContext().getResources().getDimensionPixelSize( + mKgIndicationHeight = mView.getContext().getResources().getDimensionPixelSize( + R.dimen.keyguard_indication_margin_bottom) + + mView.getContext().getResources().getDimensionPixelSize( R.dimen.keyguard_indication_bottom_padding); updateLockIconLocation(); } @@ -288,20 +303,29 @@ public class LockIconViewController extends ViewController<LockIconView> impleme private void updateLockIconLocation() { if (mHasUdfps) { FingerprintSensorPropertiesInternal props = mAuthController.getUdfpsProps().get(0); - mView.setLocation(new PointF(props.sensorLocationX, props.sensorLocationY), + mView.setCenterLocation(new PointF(props.sensorLocationX, props.sensorLocationY), props.sensorRadius); } else { final float distAboveKgBottomArea = 12 * mDensity; final float radius = 36 * mDensity; - mView.setLocation( + final int kgBottomAreaHeight = Math.max(mKgIndicationHeight, mAmbientIndicationHeight); + mView.setCenterLocation( new PointF(mWidthPixels / 2, - mHeightPixels - mIndicationBottomPadding - distAboveKgBottomArea - radius), - (int) radius); + mHeightPixels - kgBottomAreaHeight - distAboveKgBottomArea + - radius / 2), (int) radius); } mView.getHitRect(mSensorTouchLocation); } + /** + * Set the location of ambient indication if showing (ie: now playing) + */ + public void setAmbientIndicationBottomPadding(int ambientIndicationBottomPadding) { + mAmbientIndicationHeight = ambientIndicationBottomPadding; + updateLockIconLocation(); + } + @Override public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) { pw.println("mUdfpsEnrolled: " + mUdfpsEnrolled); diff --git a/packages/SystemUI/src/com/android/keyguard/PasswordTextView.java b/packages/SystemUI/src/com/android/keyguard/PasswordTextView.java index b80f8bd64dcf..b1597144d237 100644 --- a/packages/SystemUI/src/com/android/keyguard/PasswordTextView.java +++ b/packages/SystemUI/src/com/android/keyguard/PasswordTextView.java @@ -21,6 +21,7 @@ import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ValueAnimator; import android.content.Context; +import android.content.res.Configuration; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Color; @@ -87,7 +88,7 @@ public class PasswordTextView extends View { /** * The raw text size, will be multiplied by the scaled density when drawn */ - private final int mTextHeightRaw; + private int mTextHeightRaw; private final int mGravity; private ArrayList<CharState> mTextChars = new ArrayList<>(); private String mText = ""; @@ -147,6 +148,7 @@ public class PasswordTextView extends View { } finally { a.recycle(); } + mDrawPaint.setFlags(Paint.SUBPIXEL_TEXT_FLAG | Paint.ANTI_ALIAS_FLAG); mDrawPaint.setTextAlign(Paint.Align.CENTER); mDrawPaint.setTypeface(Typeface.create( @@ -164,6 +166,12 @@ public class PasswordTextView extends View { } @Override + protected void onConfigurationChanged(Configuration newConfig) { + mTextHeightRaw = getContext().getResources().getInteger( + R.integer.scaled_password_text_size); + } + + @Override protected void onDraw(Canvas canvas) { float totalDrawingWidth = getDrawingWidth(); float currentDrawPosition; diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java index 17178fa8e606..e521c90961fb 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java @@ -310,7 +310,8 @@ class MagnificationModeSwitch implements MagnificationGestureDetector.OnGestureL } void onConfigurationChanged(int configDiff) { - if ((configDiff & ActivityInfo.CONFIG_ORIENTATION) != 0) { + if ((configDiff & (ActivityInfo.CONFIG_ORIENTATION | ActivityInfo.CONFIG_SCREEN_SIZE)) + != 0) { final Rect previousDraggableBounds = new Rect(mDraggableWindowBounds); mDraggableWindowBounds.set(getDraggableWindowBounds()); // Keep the Y position with the same height ratio before the window bounds and diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java index cee395bd9a6a..32813479dc0a 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java @@ -91,7 +91,7 @@ public class WindowMagnification extends SystemUI implements WindowMagnifierCall final Context windowContext = mContext.createWindowContext(display, TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY, /* options */ null); final WindowMagnificationController controller = new WindowMagnificationController( - mContext, + windowContext, mHandler, new SfVsyncFrameCallbackProvider(), null, new SurfaceControl.Transaction(), mWindowMagnifierCallback, mSysUiState); return new WindowMagnificationAnimationController(windowContext, controller); diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintView.java index c4f58806c26c..205054d68280 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintView.java @@ -90,6 +90,7 @@ public class AuthBiometricFaceToFingerprintView extends AuthBiometricFaceView { } @Modality private int mActiveSensorType = TYPE_FACE; + @Nullable private ModalityListener mModalityListener; @Nullable private FingerprintSensorPropertiesInternal mFingerprintSensorProps; @Nullable private UdfpsDialogMeasureAdapter mUdfpsMeasureAdapter; @@ -115,6 +116,10 @@ public class AuthBiometricFaceToFingerprintView extends AuthBiometricFaceView { return mFingerprintSensorProps.isAnyUdfpsType(); } + void setModalityListener(@NonNull ModalityListener listener) { + mModalityListener = listener; + } + void setFingerprintSensorProps(@NonNull FingerprintSensorPropertiesInternal sensorProps) { mFingerprintSensorProps = sensorProps; } @@ -182,11 +187,16 @@ public class AuthBiometricFaceToFingerprintView extends AuthBiometricFaceView { @Override public void updateState(@BiometricState int newState) { if (mState == STATE_HELP || mState == STATE_ERROR) { + @Modality final int currentType = mActiveSensorType; mActiveSensorType = TYPE_FINGERPRINT; setRequireConfirmation(false); mConfirmButton.setEnabled(false); mConfirmButton.setVisibility(View.GONE); + + if (mModalityListener != null && currentType != mActiveSensorType) { + mModalityListener.onModalitySwitched(currentType, mActiveSensorType); + } } super.updateState(newState); diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java index d5f74951c6f7..bebf813e1833 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java @@ -759,6 +759,9 @@ public abstract class AuthBiometricView extends LinearLayout { // Restore positive button(s) state mConfirmButton.setVisibility( mSavedState.getInt(AuthDialog.KEY_BIOMETRIC_CONFIRM_VISIBILITY)); + if (mConfirmButton.getVisibility() == View.GONE) { + setRequireConfirmation(false); + } mTryAgainButton.setVisibility( mSavedState.getInt(AuthDialog.KEY_BIOMETRIC_TRY_AGAIN_VISIBILITY)); diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java index fd1313fc9d1d..3f61d3c6af9a 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java @@ -24,7 +24,6 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.graphics.PixelFormat; -import android.hardware.biometrics.BiometricAuthenticator; import android.hardware.biometrics.BiometricAuthenticator.Modality; import android.hardware.biometrics.BiometricConstants; import android.hardware.biometrics.PromptInfo; @@ -37,6 +36,7 @@ import android.os.IBinder; import android.os.Looper; import android.os.UserManager; import android.util.Log; +import android.view.Display; import android.view.Gravity; import android.view.KeyEvent; import android.view.LayoutInflater; @@ -356,6 +356,12 @@ public class AuthContainerView extends LinearLayout (AuthBiometricFaceToFingerprintView) factory.inflate( R.layout.auth_biometric_face_to_fingerprint_view, null, false); faceToFingerprintView.setFingerprintSensorProps(fingerprintSensorProps); + faceToFingerprintView.setModalityListener(new ModalityListener() { + @Override + public void onModalitySwitched(int oldModality, int newModality) { + maybeUpdatePositionForUdfps(true /* invalidate */); + } + }); mBiometricView = faceToFingerprintView; } else { Log.e(TAG, "Fingerprint props not found for sensor ID: " + fingerprintSensorId); @@ -471,6 +477,11 @@ public class AuthContainerView extends LinearLayout } @Override + public void onOrientationChanged() { + maybeUpdatePositionForUdfps(true /* invalidate */); + } + + @Override public void onAttachedToWindow() { super.onAttachedToWindow(); onAttachedToWindowInternal(); @@ -489,9 +500,7 @@ public class AuthContainerView extends LinearLayout + mConfig.mPromptInfo.getAuthenticators()); } - if (shouldUpdatePositionForUdfps()) { - updatePositionForUdfps(); - } + maybeUpdatePositionForUdfps(false /* invalidate */); if (mConfig.mSkipIntro) { mContainerState = STATE_SHOWING; @@ -536,14 +545,14 @@ public class AuthContainerView extends LinearLayout } } - private boolean shouldUpdatePositionForUdfps() { - if (mBiometricView instanceof AuthBiometricUdfpsView) { + private static boolean shouldUpdatePositionForUdfps(@NonNull View view) { + if (view instanceof AuthBiometricUdfpsView) { return true; } - if (mBiometricView instanceof AuthBiometricFaceToFingerprintView) { + if (view instanceof AuthBiometricFaceToFingerprintView) { AuthBiometricFaceToFingerprintView faceToFingerprintView = - (AuthBiometricFaceToFingerprintView) mBiometricView; + (AuthBiometricFaceToFingerprintView) view; return faceToFingerprintView.getActiveSensorType() == TYPE_FINGERPRINT && faceToFingerprintView.isFingerprintUdfps(); } @@ -551,8 +560,16 @@ public class AuthContainerView extends LinearLayout return false; } - private void updatePositionForUdfps() { - final int displayRotation = getDisplay().getRotation(); + private boolean maybeUpdatePositionForUdfps(boolean invalidate) { + final Display display = getDisplay(); + if (display == null) { + return false; + } + if (!shouldUpdatePositionForUdfps(mBiometricView)) { + return false; + } + + final int displayRotation = display.getRotation(); switch (displayRotation) { case Surface.ROTATION_0: mPanelController.setPosition(AuthPanelController.POSITION_BOTTOM); @@ -576,6 +593,13 @@ public class AuthContainerView extends LinearLayout setScrollViewGravity(Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM); break; } + + if (invalidate) { + mPanelView.invalidateOutline(); + mBiometricView.requestLayout(); + } + + return true; } private void setScrollViewGravity(int gravity) { @@ -626,13 +650,6 @@ public class AuthContainerView extends LinearLayout @Override public void onAuthenticationFailed(@Modality int modality, String failureReason) { mBiometricView.onAuthenticationFailed(modality, failureReason); - if (mBiometricView instanceof AuthBiometricFaceToFingerprintView - && ((AuthBiometricFaceToFingerprintView) mBiometricView).isFingerprintUdfps() - && modality == BiometricAuthenticator.TYPE_FACE) { - updatePositionForUdfps(); - mPanelView.invalidateOutline(); - mBiometricView.requestLayout(); - } } @Override diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java index 7947241ff794..71e2bb657de4 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java @@ -30,7 +30,6 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.res.Configuration; import android.graphics.PointF; -import android.graphics.RectF; import android.hardware.biometrics.BiometricAuthenticator.Modality; import android.hardware.biometrics.BiometricConstants; import android.hardware.biometrics.BiometricManager.Authenticators; @@ -70,6 +69,8 @@ import java.util.Set; import javax.inject.Inject; import javax.inject.Provider; +import kotlin.Unit; + /** * Receives messages sent from {@link com.android.server.biometrics.BiometricService} and shows the * appropriate biometric UI (e.g. BiometricDialogView). @@ -97,17 +98,16 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, @VisibleForTesting AuthDialog mCurrentDialog; - private WindowManager mWindowManager; - @Nullable - private UdfpsController mUdfpsController; - @Nullable - private IUdfpsHbmListener mUdfpsHbmListener; - @Nullable - private SidefpsController mSidefpsController; + @NonNull private final WindowManager mWindowManager; + @Nullable private UdfpsController mUdfpsController; + @Nullable private IUdfpsHbmListener mUdfpsHbmListener; + @Nullable private SidefpsController mSidefpsController; @VisibleForTesting TaskStackListener mTaskStackListener; @VisibleForTesting IBiometricSysuiReceiver mReceiver; + @VisibleForTesting + @NonNull final BiometricOrientationEventListener mOrientationListener; @Nullable private final List<FaceSensorPropertiesInternal> mFaceProps; @Nullable private List<FingerprintSensorPropertiesInternal> mFpProps; @Nullable private List<FingerprintSensorPropertiesInternal> mUdfpsProps; @@ -164,6 +164,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, Log.w(TAG, "ACTION_CLOSE_SYSTEM_DIALOGS received"); mCurrentDialog.dismissWithoutCallback(true /* animate */); mCurrentDialog = null; + mOrientationListener.disable(); try { if (mReceiver != null) { @@ -192,6 +193,8 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, Log.w(TAG, "Evicting client due to: " + topPackage); mCurrentDialog.dismissWithoutCallback(true /* animate */); mCurrentDialog = null; + mOrientationListener.disable(); + if (mReceiver != null) { mReceiver.onDialogDismissed( BiometricPrompt.DISMISSED_REASON_USER_CANCEL, @@ -342,15 +345,6 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, /** * @return where the UDFPS exists on the screen in pixels in portrait mode. */ - @Nullable public RectF getUdfpsRegion() { - return mUdfpsController == null - ? null - : mUdfpsController.getSensorLocation(); - } - - /** - * @return where the UDFPS exists on the screen in pixels in portrait mode. - */ @Nullable public PointF getUdfpsSensorLocation() { if (mUdfpsController == null) { return null; @@ -422,8 +416,10 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, } @Inject - public AuthController(Context context, CommandQueue commandQueue, + public AuthController(Context context, + CommandQueue commandQueue, ActivityTaskManager activityTaskManager, + @NonNull WindowManager windowManager, @Nullable FingerprintManager fingerprintManager, @Nullable FaceManager faceManager, Provider<UdfpsController> udfpsControllerFactory, @@ -435,6 +431,11 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, mFaceManager = faceManager; mUdfpsControllerFactory = udfpsControllerFactory; mSidefpsControllerFactory = sidefpsControllerFactory; + mWindowManager = windowManager; + mOrientationListener = new BiometricOrientationEventListener(context, () -> { + onOrientationChanged(); + return Unit.INSTANCE; + }); mFaceProps = mFaceManager != null ? mFaceManager.getSensorPropertiesInternal() : null; @@ -462,7 +463,6 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, @Override public void start() { mCommandQueue.addCallback(this); - mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); if (mFingerprintManager != null) { mFingerprintManager.addAuthenticatorsRegisteredCallback( @@ -630,6 +630,18 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, // BiometricService will have already sent the callback to the client in this case. // This avoids a round trip to SystemUI. So, just dismiss the dialog and we're done. mCurrentDialog = null; + mOrientationListener.disable(); + } + + /** + * Whether the user's finger is currently on udfps attempting to authenticate. + */ + public boolean isUdfpsFingerDown() { + if (mUdfpsController == null) { + return false; + } + + return mUdfpsController.isFingerDown(); } /** @@ -701,6 +713,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, mReceiver = (IBiometricSysuiReceiver) args.arg2; mCurrentDialog = newDialog; mCurrentDialog.show(mWindowManager, savedState); + mOrientationListener.enable(); } private void onDialogDismissed(@DismissedReason int reason) { @@ -710,20 +723,12 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, } mReceiver = null; mCurrentDialog = null; + mOrientationListener.disable(); } @Override protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); - // UdfpsController is not BiometricPrompt-specific. It can be active for keyguard or - // enrollment. - if (mUdfpsController != null) { - mUdfpsController.onConfigurationChanged(); - } - - if (mSidefpsController != null) { - mSidefpsController.onConfigurationChanged(); - } // Save the state of the current dialog (buttons showing, etc) if (mCurrentDialog != null) { @@ -731,6 +736,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, mCurrentDialog.onSaveState(savedState); mCurrentDialog.dismissWithoutCallback(false /* animate */); mCurrentDialog = null; + mOrientationListener.disable(); // Only show the dialog if necessary. If it was animating out, the dialog is supposed // to send its pending callback immediately. @@ -751,6 +757,12 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, } } + private void onOrientationChanged() { + if (mCurrentDialog != null) { + mCurrentDialog.onOrientationChanged(); + } + } + protected AuthDialog buildDialog(PromptInfo promptInfo, boolean requireConfirmation, int userId, int[] sensorIds, boolean credentialAllowed, String opPackageName, boolean skipIntro, long operationId, diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialog.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialog.java index ff31e499f6e8..fa5213e94081 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialog.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialog.java @@ -156,4 +156,12 @@ public interface AuthDialog { * @return true if device credential is allowed. */ boolean isAllowDeviceCredentials(); + + /** + * Called when the device's orientation changed and the dialog may need to do another + * layout. This is most relevant to UDFPS since configuration changes are not sent by + * the framework in equivalent cases (landscape to reverse landscape) but the dialog + * must remain fixed on the physical sensor location. + */ + void onOrientationChanged(); } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricOrientationEventListener.kt b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricOrientationEventListener.kt new file mode 100644 index 000000000000..08ea857eb208 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricOrientationEventListener.kt @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.biometrics + +import android.content.Context +import android.view.OrientationEventListener + +/** + * An [OrientationEventListener] that invokes the [onOrientationChanged] callback whenever + * the orientation of the device has changed in order to keep overlays for biometric sensors + * aligned with the device's screen. + */ +class BiometricOrientationEventListener( + private val context: Context, + private val onOrientationChanged: () -> Unit +) : OrientationEventListener(context) { + + /** If actively listening (not available in base class). */ + var enabled: Boolean = false + private set + + private var lastRotation = context.display?.rotation ?: ORIENTATION_UNKNOWN + + override fun onOrientationChanged(orientation: Int) { + if (orientation == ORIENTATION_UNKNOWN) { + return + } + + val rotation = context.display?.rotation ?: return + if (lastRotation != rotation) { + lastRotation = rotation + + onOrientationChanged() + } + } + + override fun enable() { + enabled = true + super.enable() + } + + override fun disable() { + enabled = false + super.disable() + } +} diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ModalityListener.java b/packages/SystemUI/src/com/android/systemui/biometrics/ModalityListener.java new file mode 100644 index 000000000000..c162f7dec452 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/biometrics/ModalityListener.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.biometrics; + +import android.hardware.biometrics.BiometricAuthenticator.Modality; + +/** + * Listener for events related to modality changes during operations. + * + * Used by views such as {@link AuthBiometricFaceToFingerprintView} that support fallback style + * authentication. + */ +public interface ModalityListener { + + /** + * The modality has changed. Called after the transition has been fully completed. + * + * @param oldModality original modality + * @param newModality current modality + */ + default void onModalitySwitched(@Modality int oldModality, @Modality int newModality) {} +} diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/SidefpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/SidefpsController.java index a52296a71960..a51c2b802b91 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/SidefpsController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/SidefpsController.java @@ -41,6 +41,8 @@ import com.android.systemui.util.concurrency.DelayableExecutor; import javax.inject.Inject; +import kotlin.Unit; + /** * Shows and hides the side fingerprint sensor (side-fps) overlay and handles side fps touch events. */ @@ -52,6 +54,8 @@ public class SidefpsController { private final FingerprintManager mFingerprintManager; private final WindowManager mWindowManager; private final DelayableExecutor mFgExecutor; + @VisibleForTesting @NonNull final BiometricOrientationEventListener mOrientationListener; + // TODO: update mDisplayHeight and mDisplayWidth for multi-display devices private final int mDisplayHeight; private final int mDisplayWidth; @@ -95,6 +99,10 @@ public class SidefpsController { mFingerprintManager = checkNotNull(fingerprintManager); mWindowManager = windowManager; mFgExecutor = fgExecutor; + mOrientationListener = new BiometricOrientationEventListener(context, () -> { + onOrientationChanged(); + return Unit.INSTANCE; + }); mSensorProps = findFirstSidefps(); checkArgument(mSensorProps != null); @@ -119,14 +127,15 @@ public class SidefpsController { mFingerprintManager.setSidefpsController(mSidefpsControllerImpl); } - void show() { + private void show() { mView = (SidefpsView) mInflater.inflate(R.layout.sidefps_view, null, false); mView.setSensorProperties(mSensorProps); mWindowManager.addView(mView, computeLayoutParams()); + mOrientationListener.enable(); } - void hide() { + private void hide() { if (mView != null) { mWindowManager.removeView(mView); mView.setOnTouchListener(null); @@ -135,14 +144,16 @@ public class SidefpsController { } else { Log.v(TAG, "hideUdfpsOverlay | the overlay is already hidden"); } - } + mOrientationListener.disable(); + } - void onConfigurationChanged() { + private void onOrientationChanged() { // If mView is null or if view is hidden, then return. if (mView == null || !mIsVisible) { return; } + // If the overlay needs to be displayed with a new configuration, destroy the current // overlay, and re-create and show the overlay with the updated LayoutParams. hide(); diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java index c5a0dfb45eda..e51baed065ef 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java @@ -16,6 +16,7 @@ package com.android.systemui.biometrics; +import static android.hardware.fingerprint.IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD; import static android.os.VibrationEffect.Composition.PRIMITIVE_LOW_TICK; import static com.android.internal.util.Preconditions.checkArgument; @@ -79,6 +80,8 @@ import java.util.Optional; import javax.inject.Inject; +import kotlin.Unit; + /** * Shows and hides the under-display fingerprint sensor (UDFPS) overlay, handles UDFPS touch events, * and coordinates triggering of the high-brightness mode (HBM). @@ -118,6 +121,7 @@ public class UdfpsController implements DozeReceiver { @NonNull private final AccessibilityManager mAccessibilityManager; @NonNull private final LockscreenShadeTransitionController mLockscreenShadeTransitionController; @Nullable private final UdfpsHbmProvider mHbmProvider; + @VisibleForTesting @NonNull final BiometricOrientationEventListener mOrientationListener; // Currently the UdfpsController supports a single UDFPS sensor. If devices have multiple // sensors, this, in addition to a lot of the code here, will be updated. @VisibleForTesting final FingerprintSensorPropertiesInternal mSensorProps; @@ -314,8 +318,10 @@ public class UdfpsController implements DozeReceiver { @Override public void onReceive(Context context, Intent intent) { if (mServerRequest != null + && mServerRequest.mRequestReason != REASON_AUTH_FPM_KEYGUARD && Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) { - Log.d(TAG, "ACTION_CLOSE_SYSTEM_DIALOGS received"); + Log.d(TAG, "ACTION_CLOSE_SYSTEM_DIALOGS received, mRequestReason: " + + mServerRequest.mRequestReason); mServerRequest.onUserCanceled(); mServerRequest = null; updateOverlay(); @@ -511,6 +517,10 @@ public class UdfpsController implements DozeReceiver { mHbmProvider = hbmProvider.orElse(null); screenLifecycle.addObserver(mScreenObserver); mScreenOn = screenLifecycle.getScreenState() == ScreenLifecycle.SCREEN_ON; + mOrientationListener = new BiometricOrientationEventListener(context, () -> { + onOrientationChanged(); + return Unit.INSTANCE; + }); mSensorProps = findFirstUdfps(); // At least one UDFPS sensor exists @@ -626,9 +636,12 @@ public class UdfpsController implements DozeReceiver { // Gets the size based on the current rotation of the display. mContext.getDisplay().getRealSize(p); - // Transform dimensions if the device is in landscape mode. + // Transform dimensions if the device is in landscape mode switch (mContext.getDisplay().getRotation()) { case Surface.ROTATION_90: + if (animation instanceof UdfpsKeyguardViewController) { + break; + } mCoreLayoutParams.x = mSensorProps.sensorLocationY - mSensorProps.sensorRadius - paddingX; mCoreLayoutParams.y = p.y - mSensorProps.sensorLocationX - mSensorProps.sensorRadius @@ -636,6 +649,9 @@ public class UdfpsController implements DozeReceiver { break; case Surface.ROTATION_270: + if (animation instanceof UdfpsKeyguardViewController) { + break; + } mCoreLayoutParams.x = p.x - mSensorProps.sensorLocationY - mSensorProps.sensorRadius - paddingX; mCoreLayoutParams.y = mSensorProps.sensorLocationX - mSensorProps.sensorRadius @@ -644,13 +660,14 @@ public class UdfpsController implements DozeReceiver { default: // Do nothing to stay in portrait mode. + // Keyguard is always in portrait mode. } // avoid announcing window title mCoreLayoutParams.accessibilityTitle = " "; return mCoreLayoutParams; } - void onConfigurationChanged() { + private void onOrientationChanged() { // When the configuration changes it's almost always necessary to destroy and re-create // the overlay's window to pass it the new LayoutParams. // Hiding the overlay will destroy its window. It's safe to hide the overlay regardless @@ -663,10 +680,12 @@ public class UdfpsController implements DozeReceiver { private void showUdfpsOverlay(@NonNull ServerRequest request) { mExecution.assertIsMainThread(); + final int reason = request.mRequestReason; if (mView == null) { try { Log.v(TAG, "showUdfpsOverlay | adding window reason=" + reason); + mView = (UdfpsView) mInflater.inflate(R.layout.udfps_view, null, false); mOnFingerDown = false; mView.setSensorProperties(mSensorProps); @@ -674,6 +693,7 @@ public class UdfpsController implements DozeReceiver { UdfpsAnimationViewController animation = inflateUdfpsAnimation(reason); animation.init(); mView.setAnimationViewController(animation); + mOrientationListener.enable(); // This view overlaps the sensor area, so prevent it from being selectable // during a11y. @@ -751,22 +771,24 @@ public class UdfpsController implements DozeReceiver { } private void hideUdfpsOverlay() { - mFgExecutor.execute(() -> { - if (mView != null) { - Log.v(TAG, "hideUdfpsOverlay | removing window"); - // Reset the controller back to its starting state. - onFingerUp(); - mWindowManager.removeView(mView); - mView.setOnTouchListener(null); - mView.setOnHoverListener(null); - mView.setAnimationViewController(null); - mAccessibilityManager.removeTouchExplorationStateChangeListener( - mTouchExplorationStateChangeListener); - mView = null; - } else { - Log.v(TAG, "hideUdfpsOverlay | the overlay is already hidden"); - } - }); + mExecution.assertIsMainThread(); + + if (mView != null) { + Log.v(TAG, "hideUdfpsOverlay | removing window"); + // Reset the controller back to its starting state. + onFingerUp(); + mWindowManager.removeView(mView); + mView.setOnTouchListener(null); + mView.setOnHoverListener(null); + mView.setAnimationViewController(null); + mAccessibilityManager.removeTouchExplorationStateChangeListener( + mTouchExplorationStateChangeListener); + mView = null; + } else { + Log.v(TAG, "hideUdfpsOverlay | the overlay is already hidden"); + } + + mOrientationListener.disable(); } /** @@ -821,6 +843,10 @@ public class UdfpsController implements DozeReceiver { mIsAodInterruptActive = false; } + public boolean isFingerDown() { + return mOnFingerDown; + } + private void onFingerDown(int x, int y, float minor, float major) { mExecution.assertIsMainThread(); if (mView == null) { diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java index 91cc149be800..3dab010d917c 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java @@ -71,12 +71,6 @@ public class UdfpsEnrollViewController extends UdfpsAnimationViewController<Udfp } } - @Override - protected void onViewDetached() { - super.onViewDetached(); - mEnrollHelper.setListener(null); - } - @NonNull @Override public PointF getTouchTranslation() { diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java index ec96af3ef500..131618442c22 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java @@ -43,6 +43,7 @@ import com.android.systemui.statusbar.StatusBarState; import com.airbnb.lottie.LottieAnimationView; import com.airbnb.lottie.LottieProperty; import com.airbnb.lottie.model.KeyPath; + /** * View corresponding with udfps_keyguard_view.xml */ @@ -114,12 +115,10 @@ public class UdfpsKeyguardView extends UdfpsAnimationView { @Override void onIlluminationStarting() { - setVisibility(View.INVISIBLE); } @Override void onIlluminationStopped() { - setVisibility(View.VISIBLE); } @Override @@ -140,9 +139,12 @@ public class UdfpsKeyguardView extends UdfpsAnimationView { mAodFp.setTranslationX(mBurnInOffsetX); mAodFp.setTranslationY(mBurnInOffsetY); mAodFp.setProgress(mBurnInProgress); + mAodFp.setAlpha(255 * mInterpolatedDarkAmount); mLockScreenFp.setTranslationX(mBurnInOffsetX); mLockScreenFp.setTranslationY(mBurnInOffsetY); + mLockScreenFp.setProgress(1f - mInterpolatedDarkAmount); + mLockScreenFp.setAlpha((1f - mInterpolatedDarkAmount) * 255); } void requestUdfps(boolean request, int color) { @@ -209,14 +211,6 @@ public class UdfpsKeyguardView extends UdfpsAnimationView { mHintAnimator.cancel(); mInterpolatedDarkAmount = eased; updateBurnInOffsets(); - mLockScreenFp.setProgress(1f - mInterpolatedDarkAmount); - mAodFp.setAlpha(mInterpolatedDarkAmount); - - if (linear == 1f) { - mLockScreenFp.setVisibility(View.INVISIBLE); - } else { - mLockScreenFp.setVisibility(View.VISIBLE); - } } void animateHint() { diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java index 819de538c840..51124fb28ad1 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java @@ -41,6 +41,7 @@ import com.android.systemui.util.concurrency.DelayableExecutor; import java.io.FileDescriptor; import java.io.PrintWriter; + /** * Class that coordinates non-HBM animations during keyguard authentication. * @@ -66,6 +67,7 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud private boolean mHintShown; private int mStatusBarState; private float mTransitionToFullShadeProgress; + private float mLastDozeAmount; /** * hidden amount of pin/pattern/password bouncer @@ -108,6 +110,7 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud updateFaceDetectRunning(mKeyguardUpdateMonitor.isFaceDetectionRunning()); final float dozeAmount = mStatusBarStateController.getDozeAmount(); + mLastDozeAmount = dozeAmount; mStateListener.onDozeAmountChanged(dozeAmount, dozeAmount); mStatusBarStateController.addCallback(mStateListener); @@ -205,7 +208,7 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud return true; } - if (mInputBouncerHiddenAmount < .4f || mIsBouncerVisible) { + if (mInputBouncerHiddenAmount < .5f || mIsBouncerVisible) { return true; } @@ -277,8 +280,9 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud private void updateAlpha() { // fade icon on transition to showing bouncer int alpha = mShowingUdfpsBouncer ? 255 - : Math.abs((int) MathUtils.constrainedMap(0f, 255f, .4f, .7f, - mInputBouncerHiddenAmount)); + : (int) MathUtils.constrain( + MathUtils.map(.5f, .9f, 0f, 255f, mInputBouncerHiddenAmount), + 0f, 255f); alpha *= (1.0f - mTransitionToFullShadeProgress); mView.setUnpausedAlpha(alpha); } @@ -287,8 +291,11 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud new StatusBarStateController.StateListener() { @Override public void onDozeAmountChanged(float linear, float eased) { - if (linear != 0) showUdfpsBouncer(false); + if (mLastDozeAmount < linear) { + showUdfpsBouncer(false); + } mView.onDozeAmountChanged(linear, eased); + mLastDozeAmount = linear; updatePauseAuth(); } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java index 809e7a70d66c..37a6cfaabb5e 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java @@ -33,7 +33,6 @@ import com.android.internal.logging.MetricsLogger; import com.android.systemui.classifier.FalsingDataProvider.SessionListener; import com.android.systemui.classifier.HistoryTracker.BeliefListener; import com.android.systemui.dagger.qualifiers.TestHarness; -import com.android.systemui.dock.DockManager; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.statusbar.policy.KeyguardStateController; @@ -66,7 +65,6 @@ public class BrightLineFalsingManager implements FalsingManager { private static final double FALSE_BELIEF_THRESHOLD = 0.9; private final FalsingDataProvider mDataProvider; - private final DockManager mDockManager; private final SingleTapClassifier mSingleTapClassifier; private final DoubleTapClassifier mDoubleTapClassifier; private final HistoryTracker mHistoryTracker; @@ -173,14 +171,13 @@ public class BrightLineFalsingManager implements FalsingManager { @Inject public BrightLineFalsingManager(FalsingDataProvider falsingDataProvider, - DockManager dockManager, MetricsLogger metricsLogger, + MetricsLogger metricsLogger, @Named(BRIGHT_LINE_GESTURE_CLASSIFERS) Set<FalsingClassifier> classifiers, SingleTapClassifier singleTapClassifier, DoubleTapClassifier doubleTapClassifier, HistoryTracker historyTracker, KeyguardStateController keyguardStateController, AccessibilityManager accessibilityManager, @TestHarness boolean testHarness) { mDataProvider = falsingDataProvider; - mDockManager = dockManager; mMetricsLogger = metricsLogger; mClassifiers = classifiers; mSingleTapClassifier = singleTapClassifier; @@ -332,7 +329,7 @@ public class BrightLineFalsingManager implements FalsingManager { || !mKeyguardStateController.isShowing() || mTestHarness || mDataProvider.isJustUnlockedWithFace() - || mDockManager.isDocked() + || mDataProvider.isDocked() || mAccessibilityManager.isEnabled(); } @@ -400,7 +397,7 @@ public class BrightLineFalsingManager implements FalsingManager { ipw.print("mJustUnlockedWithFace="); ipw.println(mDataProvider.isJustUnlockedWithFace() ? 1 : 0); ipw.print("isDocked="); - ipw.println(mDockManager.isDocked() ? 1 : 0); + ipw.println(mDataProvider.isDocked() ? 1 : 0); ipw.print("width="); ipw.println(mDataProvider.getWidthPixels()); ipw.print("height="); diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java index 969736910b5e..14e5991f35d2 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java @@ -16,6 +16,8 @@ package com.android.systemui.classifier; +import static com.android.systemui.dock.DockManager.DockEventListener; + import android.hardware.SensorManager; import android.hardware.biometrics.BiometricSourceType; import android.util.Log; @@ -25,9 +27,12 @@ import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.dock.DockManager; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.StatusBarState; +import com.android.systemui.statusbar.policy.BatteryController; +import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.util.concurrency.DelayableExecutor; import com.android.systemui.util.sensors.ProximitySensor; @@ -53,6 +58,8 @@ class FalsingCollectorImpl implements FalsingCollector { private final ProximitySensor mProximitySensor; private final StatusBarStateController mStatusBarStateController; private final KeyguardStateController mKeyguardStateController; + private final BatteryController mBatteryController; + private final DockManager mDockManager; private final DelayableExecutor mMainExecutor; private final SystemClock mSystemClock; @@ -89,12 +96,46 @@ class FalsingCollectorImpl implements FalsingCollector { } }; + + private final BatteryStateChangeCallback mBatteryListener = new BatteryStateChangeCallback() { + @Override + public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) { + } + + @Override + public void onWirelessChargingChanged(boolean isWirelessCharging) { + if (isWirelessCharging || mDockManager.isDocked()) { + mProximitySensor.pause(); + } else { + mProximitySensor.resume(); + } + } + }; + + private final DockEventListener mDockEventListener = new DockEventListener() { + @Override + public void onEvent(int event) { + if (event == DockManager.STATE_NONE && !mBatteryController.isWirelessCharging()) { + mProximitySensor.resume(); + } else { + mProximitySensor.pause(); + } + } + }; + @Inject - FalsingCollectorImpl(FalsingDataProvider falsingDataProvider, FalsingManager falsingManager, - KeyguardUpdateMonitor keyguardUpdateMonitor, HistoryTracker historyTracker, - ProximitySensor proximitySensor, StatusBarStateController statusBarStateController, + FalsingCollectorImpl( + FalsingDataProvider falsingDataProvider, + FalsingManager falsingManager, + KeyguardUpdateMonitor keyguardUpdateMonitor, + HistoryTracker historyTracker, + ProximitySensor proximitySensor, + StatusBarStateController statusBarStateController, KeyguardStateController keyguardStateController, - @Main DelayableExecutor mainExecutor, SystemClock systemClock) { + BatteryController batteryController, + DockManager dockManager, + @Main DelayableExecutor mainExecutor, + SystemClock systemClock) { mFalsingDataProvider = falsingDataProvider; mFalsingManager = falsingManager; mKeyguardUpdateMonitor = keyguardUpdateMonitor; @@ -102,10 +143,11 @@ class FalsingCollectorImpl implements FalsingCollector { mProximitySensor = proximitySensor; mStatusBarStateController = statusBarStateController; mKeyguardStateController = keyguardStateController; + mBatteryController = batteryController; + mDockManager = dockManager; mMainExecutor = mainExecutor; mSystemClock = systemClock; - mProximitySensor.setTag(PROXIMITY_SENSOR_TAG); mProximitySensor.setDelay(SensorManager.SENSOR_DELAY_GAME); @@ -113,6 +155,9 @@ class FalsingCollectorImpl implements FalsingCollector { mState = mStatusBarStateController.getState(); mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateCallback); + + mBatteryController.addCallback(mBatteryListener); + mDockManager.addListener(mDockEventListener); } @Override @@ -312,6 +357,8 @@ class FalsingCollectorImpl implements FalsingCollector { unregisterSensors(); mKeyguardUpdateMonitor.removeCallback(mKeyguardUpdateCallback); mStatusBarStateController.removeCallback(mStatusBarStateListener); + mBatteryController.removeCallback(mBatteryListener); + mDockManager.removeListener(mDockEventListener); } @Override @@ -351,9 +398,7 @@ class FalsingCollectorImpl implements FalsingCollector { } private void registerSensors() { - if (!mFalsingDataProvider.isWirelessCharging()) { - mProximitySensor.register(mSensorEventListener); - } + mProximitySensor.register(mSensorEventListener); } private void unregisterSensors() { diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java index 2f688dd9d247..a3ecb0c0b273 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java @@ -22,6 +22,7 @@ import android.view.MotionEvent.PointerCoords; import android.view.MotionEvent.PointerProperties; import com.android.systemui.dagger.SysUISingleton; +import com.android.systemui.dock.DockManager; import com.android.systemui.statusbar.policy.BatteryController; import java.util.ArrayList; @@ -40,7 +41,8 @@ public class FalsingDataProvider { private final int mWidthPixels; private final int mHeightPixels; - private final BatteryController mBatteryController; + private BatteryController mBatteryController; + private final DockManager mDockManager; private final float mXdpi; private final float mYdpi; private final List<SessionListener> mSessionListeners = new ArrayList<>(); @@ -59,12 +61,16 @@ public class FalsingDataProvider { private boolean mJustUnlockedWithFace; @Inject - public FalsingDataProvider(DisplayMetrics displayMetrics, BatteryController batteryController) { + public FalsingDataProvider( + DisplayMetrics displayMetrics, + BatteryController batteryController, + DockManager dockManager) { mXdpi = displayMetrics.xdpi; mYdpi = displayMetrics.ydpi; mWidthPixels = displayMetrics.widthPixels; mHeightPixels = displayMetrics.heightPixels; mBatteryController = batteryController; + mDockManager = dockManager; FalsingClassifier.logInfo("xdpi, ydpi: " + getXdpi() + ", " + getYdpi()); FalsingClassifier.logInfo("width, height: " + getWidthPixels() + ", " + getHeightPixels()); @@ -219,11 +225,6 @@ public class FalsingDataProvider { return mLastMotionEvent.getY() < mFirstRecentMotionEvent.getY(); } - /** Returns true if phone is being charged without a cable. */ - public boolean isWirelessCharging() { - return mBatteryController.isWirelessCharging(); - } - private void recalculateData() { if (!mDirty) { return; @@ -357,6 +358,11 @@ public class FalsingDataProvider { mJustUnlockedWithFace = justUnlockedWithFace; } + /** Returns true if phone is sitting in a dock or is wirelessly charging. */ + public boolean isDocked() { + return mBatteryController.isWirelessCharging() || mDockManager.isDocked(); + } + /** Implement to be alerted abotu the beginning and ending of falsing tracking. */ public interface SessionListener { /** Called when the lock screen is shown and falsing-tracking begins. */ diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index 15f7a1219f3f..c33f4fa8dee4 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -175,7 +175,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable, private static final int KEYGUARD_DISPLAY_TIMEOUT_DELAY_DEFAULT = 30000; private static final long KEYGUARD_DONE_PENDING_TIMEOUT_MS = 3000; - private static final boolean DEBUG = true; + private static final boolean DEBUG = KeyguardConstants.DEBUG; private static final boolean DEBUG_SIM_STATES = KeyguardConstants.DEBUG_SIM_STATES; private final static String TAG = "KeyguardViewMediator"; @@ -1506,8 +1506,10 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable, return; } - // if the keyguard is already showing, don't bother - if (mKeyguardViewControllerLazy.get().isShowing()) { + // if the keyguard is already showing, don't bother. check flags in both files + // to account for the hiding animation which results in a delay and discrepancy + // between flags + if (mShowing && mKeyguardViewControllerLazy.get().isShowing()) { if (DEBUG) Log.d(TAG, "doKeyguard: not showing because it is already showing"); resetStateLocked(); return; diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java index 902e8c28a85d..15a70831b2f9 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java +++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java @@ -475,6 +475,13 @@ public class MediaControlPanel { @Nullable private ActivityLaunchAnimator.Controller buildLaunchAnimatorController( TransitionLayout player) { + if (!(player.getParent() instanceof ViewGroup)) { + // TODO(b/192194319): Throw instead of just logging. + Log.wtf(TAG, "Skipping player animation as it is not attached to a ViewGroup", + new Exception()); + return null; + } + // TODO(b/174236650): Make sure that the carousel indicator also fades out. // TODO(b/174236650): Instrument the animation to measure jank. return new GhostedViewLaunchAnimatorController(player, diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java index 7f42530916cf..3073f8353d38 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java @@ -42,6 +42,7 @@ import static com.android.internal.accessibility.common.ShortcutConstants.CHOOSE import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.HOME_BUTTON_LONG_PRESS_DURATION_MS; import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.NAV_BAR_HANDLE_FORCE_OPAQUE; import static com.android.systemui.recents.OverviewProxyService.OverviewProxyListener; +import static com.android.systemui.shared.recents.utilities.Utilities.isTablet; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_CLICKABLE; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY; @@ -91,6 +92,7 @@ import android.view.Display; import android.view.Gravity; import android.view.HapticFeedbackConstants; import android.view.IWindowManager; +import android.view.InsetsState; import android.view.InsetsState.InternalInsetsType; import android.view.KeyEvent; import android.view.LayoutInflater; @@ -382,6 +384,13 @@ public class NavigationBar implements View.OnAttachStateChangeListener, } @Override + public void onTaskbarStatusUpdated(boolean visible, boolean stashed) { + mNavigationBarView + .getFloatingRotationButton() + .onTaskbarStateChanged(visible, stashed); + } + + @Override public void onToggleRecentApps() { // The same case as onOverviewShown but only for 3-button navigation. mNavigationBarView.getRotationButtonController().setSkipOverrideUserLockPrefsOnce(); @@ -878,7 +887,10 @@ public class NavigationBar implements View.OnAttachStateChangeListener, if (hints == mNavigationIconHints) return; mNavigationIconHints = hints; - mNavigationBarView.setNavigationIconHints(hints); + if (!isTablet(mContext)) { + // All IME functions handled by launcher via Sysui flags for large screen + mNavigationBarView.setNavigationIconHints(hints); + } checkBarModes(); updateSystemUiStateFlags(-1); } @@ -950,7 +962,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener, @Override public void onSystemBarAttributesChanged(int displayId, @Appearance int appearance, AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme, - @Behavior int behavior, boolean isFullscreen) { + @Behavior int behavior, InsetsState requestedState, String packageName) { if (displayId != mDisplayId) { return; } diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java index 96c8c16309e8..6344c591803d 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java @@ -17,18 +17,17 @@ package com.android.systemui.navigationbar; import static android.view.Display.DEFAULT_DISPLAY; -import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR; import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON; +import static com.android.systemui.shared.recents.utilities.Utilities.isTablet; + import android.content.Context; import android.content.pm.ActivityInfo; import android.content.res.Configuration; -import android.content.res.Resources; import android.hardware.display.DisplayManager; import android.os.Bundle; import android.os.Handler; import android.os.RemoteException; -import android.util.DisplayMetrics; import android.util.Log; import android.util.SparseArray; import android.view.Display; @@ -86,8 +85,6 @@ public class NavigationBarController implements Callbacks, ConfigurationController.ConfigurationListener, NavigationModeController.ModeChangedListener, Dumpable { - private static final float TABLET_MIN_DPS = 600; - private static final String TAG = NavigationBarController.class.getSimpleName(); private final Context mContext; @@ -196,14 +193,14 @@ public class NavigationBarController implements Callbacks, mTaskbarDelegate = taskbarDelegate; mTaskbarDelegate.setOverviewProxyService(overviewProxyService, navigationBarA11yHelper, mSysUiFlagsContainer); - mIsTablet = isTablet(mContext.getResources().getConfiguration()); + mIsTablet = isTablet(mContext); mUserTracker = userTracker; } @Override public void onConfigChanged(Configuration newConfig) { boolean isOldConfigTablet = mIsTablet; - mIsTablet = isTablet(newConfig); + mIsTablet = isTablet(newConfig, mContext); boolean largeScreenChanged = mIsTablet != isOldConfigTablet; // If we folded/unfolded while in 3 button, show navbar in folded state, hide in unfolded if (largeScreenChanged && updateNavbarForTaskbar()) { @@ -275,7 +272,7 @@ public class NavigationBarController implements Callbacks, @Override public void onDisplayReady(int displayId) { Display display = mDisplayManager.getDisplay(displayId); - mIsTablet = isTablet(mContext.getResources().getConfiguration()); + mIsTablet = isTablet(mContext); createNavigationBar(display, null /* savedState */, null /* result */); } @@ -352,7 +349,9 @@ public class NavigationBarController implements Callbacks, Log.w(TAG, "Cannot get WindowManager."); return; } - final Context context = mContext.createWindowContext(display, TYPE_NAVIGATION_BAR, null); + final Context context = isOnDefaultDisplay + ? mContext + : mContext.createDisplayContext(display); NavigationBar navBar = new NavigationBar(context, mWindowManager, mAssistManagerLazy, @@ -470,15 +469,6 @@ public class NavigationBarController implements Callbacks, return mNavigationBars.get(DEFAULT_DISPLAY); } - private boolean isTablet(Configuration newConfig) { - float density = Resources.getSystem().getDisplayMetrics().density; - int size = Math.min((int) (density * newConfig.screenWidthDp), - (int) (density* newConfig.screenHeightDp)); - DisplayMetrics metrics = mContext.getResources().getDisplayMetrics(); - float densityRatio = (float) metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT; - return (size / densityRatio) >= TABLET_MIN_DPS; - } - @Override public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) { for (int i = 0; i < mNavigationBars.size(); i++) { diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java index 4816f1cf8d6a..23c066a75732 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java @@ -69,6 +69,7 @@ import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.animation.Interpolators; import com.android.systemui.model.SysUiState; +import com.android.systemui.navigationbar.RotationButton.RotationButtonUpdatesCallback; import com.android.systemui.navigationbar.buttons.ButtonDispatcher; import com.android.systemui.navigationbar.buttons.ContextualButton; import com.android.systemui.navigationbar.buttons.ContextualButtonGroup; @@ -275,14 +276,23 @@ public class NavigationBarView extends FrameLayout implements false /* inScreen */, false /* useNearestRegion */)); }; - private final Consumer<Boolean> mRotationButtonListener = (visible) -> { - if (visible) { - // If the button will actually become visible and the navbar is about to hide, - // tell the statusbar to keep it around for longer - mAutoHideController.touchAutoHide(); - } - notifyActiveTouchRegions(); - }; + private final RotationButtonUpdatesCallback mRotationButtonListener = + new RotationButtonUpdatesCallback() { + @Override + public void onVisibilityChanged(boolean visible) { + if (visible) { + // If the button will actually become visible and the navbar is about + // to hide, tell the statusbar to keep it around for longer + mAutoHideController.touchAutoHide(); + } + notifyActiveTouchRegions(); + } + + @Override + public void onPositionChanged() { + notifyActiveTouchRegions(); + } + }; private final Consumer<Boolean> mNavbarOverlayVisibilityChangeCallback = (visible) -> { if (visible) { diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButton.java b/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButton.java index e48785844347..3486c6e75931 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButton.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButton.java @@ -20,12 +20,10 @@ import android.view.View; import com.android.systemui.navigationbar.buttons.KeyButtonDrawable; -import java.util.function.Consumer; - /** Interface of a rotation button that interacts {@link RotationButtonController}. */ public interface RotationButton { void setRotationButtonController(RotationButtonController rotationButtonController); - void setVisibilityChangedCallback(Consumer<Boolean> visibilityChangedCallback); + void setUpdatesCallback(RotationButtonUpdatesCallback updatesCallback); View getCurrentView(); boolean show(); boolean hide(); @@ -39,4 +37,12 @@ public interface RotationButton { default boolean acceptRotationProposal() { return getCurrentView() != null; } + + /** + * Callback for updates provided by a rotation button + */ + interface RotationButtonUpdatesCallback { + void onVisibilityChanged(boolean isVisible); + void onPositionChanged(); + } } diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButtonController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButtonController.java index a5b7911d3b3d..196625b3630e 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButtonController.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButtonController.java @@ -46,6 +46,7 @@ import com.android.internal.logging.UiEventLoggerImpl; import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.animation.Interpolators; +import com.android.systemui.navigationbar.RotationButton.RotationButtonUpdatesCallback; import com.android.systemui.navigationbar.buttons.KeyButtonDrawable; import com.android.systemui.shared.recents.utilities.Utilities; import com.android.systemui.shared.recents.utilities.ViewRippler; @@ -140,12 +141,12 @@ public class RotationButtonController { } void setRotationButton(RotationButton rotationButton, - Consumer<Boolean> visibilityChangedCallback) { + RotationButtonUpdatesCallback updatesCallback) { mRotationButton = rotationButton; mRotationButton.setRotationButtonController(this); mRotationButton.setOnClickListener(this::onRotateSuggestionClick); mRotationButton.setOnHoverListener(this::onRotateSuggestionHover); - mRotationButton.setVisibilityChangedCallback(visibilityChangedCallback); + mRotationButton.setUpdatesCallback(updatesCallback); } void registerListeners() { diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java index 40afed30f4e2..1d4414690221 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java @@ -26,6 +26,7 @@ import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_I import android.inputmethodservice.InputMethodService; import android.os.IBinder; +import android.view.InsetsState; import com.android.internal.view.AppearanceRegion; import com.android.systemui.model.SysUiState; @@ -108,7 +109,7 @@ public class TaskbarDelegate implements CommandQueue.Callbacks { @Override public void onSystemBarAttributesChanged(int displayId, int appearance, AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme, int behavior, - boolean isFullscreen) { + InsetsState requestedState, String packageName) { mOverviewProxyService.onSystemBarAttributesChanged(displayId, behavior); } } diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/RotationContextButton.java b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/RotationContextButton.java index 6a97a3379939..ebb67af43a37 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/RotationContextButton.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/RotationContextButton.java @@ -23,10 +23,6 @@ import android.view.View; import com.android.systemui.navigationbar.RotationButton; import com.android.systemui.navigationbar.RotationButtonController; -import com.android.systemui.navigationbar.buttons.ContextualButton; -import com.android.systemui.navigationbar.buttons.KeyButtonDrawable; - -import java.util.function.Consumer; /** Containing logic for the rotation button in nav bar. */ public class RotationContextButton extends ContextualButton implements RotationButton { @@ -48,13 +44,10 @@ public class RotationContextButton extends ContextualButton implements RotationB } @Override - public void setVisibilityChangedCallback(Consumer<Boolean> visibilityChangedCallback) { - setListener(new ContextButtonListener() { - @Override - public void onVisibilityChanged(ContextualButton button, boolean visible) { - if (visibilityChangedCallback != null) { - visibilityChangedCallback.accept(visible); - } + public void setUpdatesCallback(RotationButtonUpdatesCallback updatesCallback) { + setListener((button, visible) -> { + if (updatesCallback != null) { + updatesCallback.onVisibilityChanged(visible); } }); } diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/FloatingRotationButton.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/FloatingRotationButton.java index 61118c5d26ac..46057952e079 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/FloatingRotationButton.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/FloatingRotationButton.java @@ -20,48 +20,72 @@ import android.content.Context; import android.content.res.Resources; import android.graphics.Color; import android.graphics.PixelFormat; -import android.view.Gravity; import android.view.LayoutInflater; -import android.view.Surface; import android.view.View; +import android.view.ViewGroup; import android.view.WindowManager; +import android.view.animation.AccelerateDecelerateInterpolator; +import android.widget.FrameLayout; import com.android.systemui.R; import com.android.systemui.navigationbar.RotationButton; import com.android.systemui.navigationbar.RotationButtonController; import com.android.systemui.navigationbar.buttons.KeyButtonDrawable; import com.android.systemui.navigationbar.buttons.KeyButtonView; +import com.android.systemui.navigationbar.gestural.FloatingRotationButtonPositionCalculator.Position; -import java.util.function.Consumer; - -/** Containing logic for the rotation button on the physical left bottom corner of the screen. */ +/** + * Containing logic for the rotation button on the physical left bottom corner of the screen. + */ public class FloatingRotationButton implements RotationButton { private static final float BACKGROUND_ALPHA = 0.92f; + private static final int MARGIN_ANIMATION_DURATION_MILLIS = 300; - private final Context mContext; private final WindowManager mWindowManager; + private final ViewGroup mKeyButtonContainer; private final KeyButtonView mKeyButtonView; - private final int mDiameter; - private final int mMargin; + + private final int mContainerSize; + private KeyButtonDrawable mKeyButtonDrawable; private boolean mIsShowing; private boolean mCanShow = true; + private int mDisplayRotation; + + private boolean mIsTaskbarVisible = false; + private boolean mIsTaskbarStashed = false; + + private final FloatingRotationButtonPositionCalculator mPositionCalculator; private RotationButtonController mRotationButtonController; - private Consumer<Boolean> mVisibilityChangedCallback; + private RotationButtonUpdatesCallback mUpdatesCallback; + private Position mPosition; public FloatingRotationButton(Context context) { - mContext = context; - mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); - mKeyButtonView = (KeyButtonView) LayoutInflater.from(mContext).inflate( + mWindowManager = context.getSystemService(WindowManager.class); + mKeyButtonContainer = (ViewGroup) LayoutInflater.from(context).inflate( R.layout.rotate_suggestion, null); + mKeyButtonView = mKeyButtonContainer.findViewById(R.id.rotate_suggestion); mKeyButtonView.setVisibility(View.VISIBLE); - Resources res = mContext.getResources(); - mDiameter = res.getDimensionPixelSize(R.dimen.floating_rotation_button_diameter); - mMargin = Math.max(res.getDimensionPixelSize(R.dimen.floating_rotation_button_min_margin), + Resources res = context.getResources(); + + int defaultMargin = Math.max( + res.getDimensionPixelSize(R.dimen.floating_rotation_button_min_margin), res.getDimensionPixelSize(R.dimen.rounded_corner_content_padding)); + + int taskbarMarginLeft = + res.getDimensionPixelSize(R.dimen.floating_rotation_button_taskbar_left_margin); + int taskbarMarginBottom = + res.getDimensionPixelSize(R.dimen.floating_rotation_button_taskbar_bottom_margin); + + mPositionCalculator = new FloatingRotationButtonPositionCalculator(defaultMargin, + taskbarMarginLeft, taskbarMarginBottom); + + final int diameter = res.getDimensionPixelSize(R.dimen.floating_rotation_button_diameter); + mContainerSize = diameter + Math.max(defaultMargin, Math.max(taskbarMarginLeft, + taskbarMarginBottom)); } @Override @@ -72,8 +96,8 @@ public class FloatingRotationButton implements RotationButton { } @Override - public void setVisibilityChangedCallback(Consumer<Boolean> visibilityChangedCallback) { - mVisibilityChangedCallback = visibilityChangedCallback; + public void setUpdatesCallback(RotationButtonUpdatesCallback updatesCallback) { + mUpdatesCallback = updatesCallback; } @Override @@ -86,45 +110,39 @@ public class FloatingRotationButton implements RotationButton { if (!mCanShow || mIsShowing) { return false; } + mIsShowing = true; int flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; - final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(mDiameter, mDiameter, - mMargin, mMargin, WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL, flags, + final WindowManager.LayoutParams lp = new WindowManager.LayoutParams( + mContainerSize, + mContainerSize, + 0, 0, WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL, flags, PixelFormat.TRANSLUCENT); + lp.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS; lp.setTitle("FloatingRotationButton"); lp.setFitInsetsTypes(0 /*types */); - switch (mWindowManager.getDefaultDisplay().getRotation()) { - case Surface.ROTATION_0: - lp.gravity = Gravity.BOTTOM | Gravity.LEFT; - break; - case Surface.ROTATION_90: - lp.gravity = Gravity.BOTTOM | Gravity.RIGHT; - break; - case Surface.ROTATION_180: - lp.gravity = Gravity.TOP | Gravity.RIGHT; - break; - case Surface.ROTATION_270: - lp.gravity = Gravity.TOP | Gravity.LEFT; - break; - default: - break; - } - mWindowManager.addView(mKeyButtonView, lp); + + mDisplayRotation = mWindowManager.getDefaultDisplay().getRotation(); + mPosition = mPositionCalculator + .calculatePosition(mDisplayRotation, mIsTaskbarVisible, mIsTaskbarStashed); + + lp.gravity = mPosition.getGravity(); + ((FrameLayout.LayoutParams) mKeyButtonView.getLayoutParams()).gravity = + mPosition.getGravity(); + + updateTranslation(mPosition, /* animate */ false); + + mWindowManager.addView(mKeyButtonContainer, lp); if (mKeyButtonDrawable != null && mKeyButtonDrawable.canAnimate()) { mKeyButtonDrawable.resetAnimation(); mKeyButtonDrawable.startAnimation(); } - mKeyButtonView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() { - @Override - public void onLayoutChange(View view, int i, int i1, int i2, int i3, int i4, int i5, - int i6, int i7) { - if (mIsShowing && mVisibilityChangedCallback != null) { - mVisibilityChangedCallback.accept(true); - } - mKeyButtonView.removeOnLayoutChangeListener(this); - } - }); + + if (mUpdatesCallback != null) { + mUpdatesCallback.onVisibilityChanged(true); + } + return true; } @@ -133,10 +151,10 @@ public class FloatingRotationButton implements RotationButton { if (!mIsShowing) { return false; } - mWindowManager.removeViewImmediate(mKeyButtonView); + mWindowManager.removeViewImmediate(mKeyButtonContainer); mIsShowing = false; - if (mVisibilityChangedCallback != null) { - mVisibilityChangedCallback.accept(false); + if (mUpdatesCallback != null) { + mUpdatesCallback.onVisibilityChanged(false); } return true; } @@ -183,4 +201,43 @@ public class FloatingRotationButton implements RotationButton { hide(); } } + + public void onTaskbarStateChanged(boolean taskbarVisible, boolean taskbarStashed) { + mIsTaskbarVisible = taskbarVisible; + mIsTaskbarStashed = taskbarStashed; + + if (!mIsShowing) return; + + final Position newPosition = mPositionCalculator + .calculatePosition(mDisplayRotation, mIsTaskbarVisible, mIsTaskbarStashed); + + if (newPosition.getTranslationX() != mPosition.getTranslationX() + || newPosition.getTranslationY() != mPosition.getTranslationY()) { + updateTranslation(newPosition, /* animate */ true); + mPosition = newPosition; + } + } + + private void updateTranslation(Position position, boolean animate) { + final int translationX = position.getTranslationX(); + final int translationY = position.getTranslationY(); + + if (animate) { + mKeyButtonView + .animate() + .translationX(translationX) + .translationY(translationY) + .setDuration(MARGIN_ANIMATION_DURATION_MILLIS) + .setInterpolator(new AccelerateDecelerateInterpolator()) + .withEndAction(() -> { + if (mUpdatesCallback != null && mIsShowing) { + mUpdatesCallback.onPositionChanged(); + } + }) + .start(); + } else { + mKeyButtonView.setTranslationX(translationX); + mKeyButtonView.setTranslationY(translationY); + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/FloatingRotationButtonPositionCalculator.kt b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/FloatingRotationButtonPositionCalculator.kt new file mode 100644 index 000000000000..3ce51ad331c5 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/FloatingRotationButtonPositionCalculator.kt @@ -0,0 +1,65 @@ +package com.android.systemui.navigationbar.gestural + +import android.view.Gravity +import android.view.Surface + +/** + * Calculates gravity and translation that is necessary to display + * the button in the correct position based on the current state + */ +internal class FloatingRotationButtonPositionCalculator( + private val defaultMargin: Int, + private val taskbarMarginLeft: Int, + private val taskbarMarginBottom: Int +) { + + fun calculatePosition( + currentRotation: Int, + taskbarVisible: Boolean, + taskbarStashed: Boolean + ): Position { + + val isTaskbarSide = currentRotation == Surface.ROTATION_0 + || currentRotation == Surface.ROTATION_90 + val useTaskbarMargin = isTaskbarSide && taskbarVisible && !taskbarStashed + + val gravity = resolveGravity(currentRotation) + + val marginLeft = if (useTaskbarMargin) taskbarMarginLeft else defaultMargin + val marginBottom = if (useTaskbarMargin) taskbarMarginBottom else defaultMargin + + val translationX = + if (gravity and Gravity.RIGHT == Gravity.RIGHT) { + -marginLeft + } else { + marginLeft + } + val translationY = + if (gravity and Gravity.BOTTOM == Gravity.BOTTOM) { + -marginBottom + } else { + marginBottom + } + + return Position( + gravity = gravity, + translationX = translationX, + translationY = translationY + ) + } + + data class Position( + val gravity: Int, + val translationX: Int, + val translationY: Int + ) + + private fun resolveGravity(rotation: Int): Int = + when (rotation) { + Surface.ROTATION_0 -> Gravity.BOTTOM or Gravity.LEFT + Surface.ROTATION_90 -> Gravity.BOTTOM or Gravity.RIGHT + Surface.ROTATION_180 -> Gravity.TOP or Gravity.RIGHT + Surface.ROTATION_270 -> Gravity.TOP or Gravity.LEFT + else -> throw IllegalArgumentException("Invalid rotation $rotation") + } +} diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java b/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java index 7ab4b6f200ed..a16b92f494a4 100644 --- a/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java +++ b/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java @@ -47,6 +47,7 @@ import android.content.Intent; import android.graphics.Bitmap; import android.graphics.ColorMatrix; import android.graphics.ColorMatrixColorFilter; +import android.graphics.ImageDecoder; import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; import android.graphics.text.LineBreaker; @@ -59,6 +60,7 @@ import android.text.TextUtils; import android.util.IconDrawableFactory; import android.util.Log; import android.util.Pair; +import android.util.Size; import android.util.SizeF; import android.util.TypedValue; import android.view.Gravity; @@ -79,6 +81,7 @@ import com.android.systemui.people.widget.LaunchConversationActivity; import com.android.systemui.people.widget.PeopleSpaceWidgetProvider; import com.android.systemui.people.widget.PeopleTileKey; +import java.io.IOException; import java.text.NumberFormat; import java.time.Duration; import java.util.ArrayList; @@ -178,6 +181,7 @@ public class PeopleTileViewHelper { private int mWidth; private int mHeight; private int mLayoutSize; + private boolean mIsLeftToRight; private Locale mLocale; private NumberFormat mIntegerFormat; @@ -192,6 +196,8 @@ public class PeopleTileViewHelper { mWidth = width; mHeight = height; mLayoutSize = getLayoutSize(); + mIsLeftToRight = TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()) + == View.LAYOUT_DIRECTION_LTR; } /** @@ -501,6 +507,8 @@ public class PeopleTileViewHelper { views.setViewVisibility(R.id.availability, View.VISIBLE); startPadding = mContext.getResources().getDimensionPixelSize( R.dimen.availability_dot_shown_padding); + views.setContentDescription(R.id.availability, + mContext.getString(R.string.person_available)); } else { views.setViewVisibility(R.id.availability, View.GONE); startPadding = mContext.getResources().getDimensionPixelSize( @@ -654,7 +662,7 @@ public class PeopleTileViewHelper { private RemoteViews createMissedCallRemoteViews() { RemoteViews views = setViewForContentLayout(new RemoteViews(mContext.getPackageName(), getLayoutForContent())); - views.setViewVisibility(R.id.predefined_icon, View.VISIBLE); + setPredefinedIconVisible(views); views.setViewVisibility(R.id.text_content, View.VISIBLE); views.setViewVisibility(R.id.messages_count, View.GONE); setMaxLines(views, false); @@ -673,19 +681,39 @@ public class PeopleTileViewHelper { return views; } + private void setPredefinedIconVisible(RemoteViews views) { + views.setViewVisibility(R.id.predefined_icon, View.VISIBLE); + if (mLayoutSize == LAYOUT_MEDIUM) { + int endPadding = mContext.getResources().getDimensionPixelSize( + R.dimen.before_predefined_icon_padding); + views.setViewPadding(R.id.name, mIsLeftToRight ? 0 : endPadding, 0, + mIsLeftToRight ? endPadding : 0, + 0); + } + } + private RemoteViews createNotificationRemoteViews() { RemoteViews views = setViewForContentLayout(new RemoteViews(mContext.getPackageName(), getLayoutForNotificationContent())); CharSequence sender = mTile.getNotificationSender(); - Uri image = mTile.getNotificationDataUri(); - if (image != null) { - // TODO: Use NotificationInlineImageCache - views.setImageViewUri(R.id.image, image); + Uri imageUri = mTile.getNotificationDataUri(); + if (imageUri != null) { String newImageDescription = mContext.getString( R.string.new_notification_image_content_description, mTile.getUserName()); views.setContentDescription(R.id.image, newImageDescription); views.setViewVisibility(R.id.image, View.VISIBLE); views.setViewVisibility(R.id.text_content, View.GONE); + try { + Drawable drawable = resolveImage(imageUri, mContext); + Bitmap bitmap = convertDrawableToBitmap(drawable); + views.setImageViewBitmap(R.id.image, bitmap); + } catch (IOException e) { + Log.e(TAG, "Could not decode image: " + e); + // If we couldn't load the image, show text that we have a new image. + views.setTextViewText(R.id.text_content, newImageDescription); + views.setViewVisibility(R.id.text_content, View.VISIBLE); + views.setViewVisibility(R.id.image, View.GONE); + } } else { setMaxLines(views, !TextUtils.isEmpty(sender)); CharSequence content = mTile.getNotificationContent(); @@ -703,6 +731,13 @@ public class PeopleTileViewHelper { views.setImageViewResource(R.id.predefined_icon, R.drawable.ic_message); } if (mTile.getMessagesCount() > 1) { + if (mLayoutSize == LAYOUT_MEDIUM) { + int endPadding = mContext.getResources().getDimensionPixelSize( + R.dimen.before_messages_count_padding); + views.setViewPadding(R.id.name, mIsLeftToRight ? 0 : endPadding, 0, + mIsLeftToRight ? endPadding : 0, + 0); + } views.setViewVisibility(R.id.messages_count, View.VISIBLE); views.setTextViewText(R.id.messages_count, getMessagesCountText(mTile.getMessagesCount())); @@ -720,6 +755,40 @@ public class PeopleTileViewHelper { return views; } + private Drawable resolveImage(Uri uri, Context context) throws IOException { + final ImageDecoder.Source source = + ImageDecoder.createSource(context.getContentResolver(), uri); + final Drawable drawable = + ImageDecoder.decodeDrawable(source, (decoder, info, s) -> { + onHeaderDecoded(decoder, info, s); + }); + return drawable; + } + + private static int getPowerOfTwoForSampleRatio(double ratio) { + final int k = Integer.highestOneBit((int) Math.floor(ratio)); + return Math.max(1, k); + } + + private void onHeaderDecoded(ImageDecoder decoder, ImageDecoder.ImageInfo info, + ImageDecoder.Source source) { + int widthInPx = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, mWidth, + mContext.getResources().getDisplayMetrics()); + int heightInPx = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, mHeight, + mContext.getResources().getDisplayMetrics()); + int maxIconSizeInPx = Math.max(widthInPx, heightInPx); + int minDimen = (int) (1.5 * Math.min(widthInPx, heightInPx)); + if (minDimen < maxIconSizeInPx) { + maxIconSizeInPx = minDimen; + } + final Size size = info.getSize(); + final int originalSize = Math.max(size.getHeight(), size.getWidth()); + final double ratio = (originalSize > maxIconSizeInPx) + ? originalSize * 1f / maxIconSizeInPx + : 1.0; + decoder.setTargetSampleSize(getPowerOfTwoForSampleRatio(ratio)); + } + private void setContentDescriptionForNotificationTextContent(RemoteViews views, CharSequence content, CharSequence sender) { String newTextDescriptionWithNotificationContent = mContext.getString( @@ -755,7 +824,7 @@ public class PeopleTileViewHelper { if (TextUtils.isEmpty(statusText)) { statusText = getStatusTextByType(status.getActivity()); } - views.setViewVisibility(R.id.predefined_icon, View.VISIBLE); + setPredefinedIconVisible(views); views.setTextViewText(R.id.text_content, statusText); if (status.getActivity() == ACTIVITY_BIRTHDAY @@ -865,13 +934,11 @@ public class PeopleTileViewHelper { * on the status layouts compared to all other layouts. */ private void setAvailabilityDotPadding(RemoteViews views, int resId) { - boolean isLeftToRight = TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()) - == View.LAYOUT_DIRECTION_LTR; int startPadding = mContext.getResources().getDimensionPixelSize(resId); int bottomPadding = mContext.getResources().getDimensionPixelSize( R.dimen.medium_content_padding_above_name); views.setViewPadding(R.id.medium_content, - isLeftToRight ? startPadding : 0, 0, isLeftToRight ? 0 : startPadding, + mIsLeftToRight ? startPadding : 0, 0, mIsLeftToRight ? 0 : startPadding, bottomPadding); } @@ -1069,6 +1136,7 @@ public class PeopleTileViewHelper { views.setViewPadding(R.id.content, horizontalPadding, verticalPadding, horizontalPadding, verticalPadding); + views.setViewPadding(R.id.name, 0, 0, 0, 0); // Expand the name font on medium if there's space. int heightRequiredForMaxContentText = (int) (mContext.getResources().getDimension( R.dimen.medium_height_for_max_name_text_size) / mDensity); diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java index 3320fbda6fe5..985903435b9a 100644 --- a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java +++ b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java @@ -375,7 +375,7 @@ public class PeopleSpaceWidgetManager { widgetSp.getInt(USER_ID, INVALID_USER_ID), widgetSp.getString(PACKAGE_NAME, EMPTY_STRING)); - return getTileFromPersistentStorage(key, appWidgetId); + return getTileFromPersistentStorage(key, appWidgetId, /* supplementFromStorage= */ true); } /** @@ -383,7 +383,8 @@ public class PeopleSpaceWidgetManager { * If a {@link PeopleTileKey} is not provided, fetch one from {@link SharedPreferences}. */ @Nullable - public PeopleSpaceTile getTileFromPersistentStorage(PeopleTileKey key, int appWidgetId) throws + public PeopleSpaceTile getTileFromPersistentStorage(PeopleTileKey key, int appWidgetId, + boolean supplementFromStorage) throws PackageManager.NameNotFoundException { if (!PeopleTileKey.isValid(key)) { Log.e(TAG, "PeopleTileKey invalid: " + key.toString()); @@ -412,7 +413,8 @@ public class PeopleSpaceWidgetManager { // Supplement with our storage. String contactUri = mSharedPrefs.getString(String.valueOf(appWidgetId), null); - if (contactUri != null && storedTile.build().getContactUri() == null) { + if (supplementFromStorage && contactUri != null + && storedTile.build().getContactUri() == null) { if (DEBUG) Log.d(TAG, "Restore contact uri from storage: " + contactUri); storedTile.setContactUri(Uri.parse(contactUri)); } @@ -811,7 +813,8 @@ public class PeopleSpaceWidgetManager { if (DEBUG) Log.d(TAG, "addNewWidget called with key for appWidgetId: " + appWidgetId); PeopleSpaceTile tile = null; try { - tile = getTileFromPersistentStorage(key, appWidgetId); + tile = getTileFromPersistentStorage(key, appWidgetId, /* supplementFromStorage= */ + false); } catch (PackageManager.NameNotFoundException e) { Log.e(TAG, "Cannot add widget since app was uninstalled"); return; @@ -850,7 +853,9 @@ public class PeopleSpaceWidgetManager { } catch (Exception e) { Log.w(TAG, "Exception caching shortcut:" + e); } - updateAppWidgetOptionsAndView(appWidgetId, tile); + PeopleSpaceTile finalTile = tile; + mBgExecutor.execute( + () -> updateAppWidgetOptionsAndView(appWidgetId, finalTile)); } /** Registers a conversation listener for {@code appWidgetId} if not already registered. */ @@ -1071,7 +1076,7 @@ public class PeopleSpaceWidgetManager { return; } for (int appWidgetId : appWidgetIds) { - if (DEBUG) Log.d(TAG, "Updating widget from broadcast, widget id: " + appWidgetId); + if (DEBUG) Log.d(TAG, "Updating widget from broadcast, widget id: " + appWidgetId); PeopleSpaceTile existingTile = null; PeopleSpaceTile updatedTile = null; try { diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java index 8c2c373fae64..a3180738fa60 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java @@ -140,9 +140,11 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha updateAnimators(); } - - public void onQsScrollingChanged() { - // Lazily update animators whenever the scrolling changes + /** + * Request an update to the animators. This will update them lazily next time the position + * is changed. + */ + public void requestAnimatorUpdate() { mNeedsAnimatorUpdate = true; } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java index bcce87a51097..1d6c7c94dcc3 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java @@ -44,6 +44,7 @@ import com.android.systemui.Dependency; import com.android.systemui.FontSizeUtils; import com.android.systemui.R; import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.DetailAdapter; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer; @@ -57,6 +58,7 @@ public class QSDetail extends LinearLayout { private final UiEventLogger mUiEventLogger = QSEvents.INSTANCE.getQsUiEventsLogger(); private ViewGroup mDetailContent; + private FalsingManager mFalsingManager; protected TextView mDetailSettingsButton; protected TextView mDetailDoneButton; @VisibleForTesting @@ -124,12 +126,13 @@ public class QSDetail extends LinearLayout { /** */ public void setQsPanel(QSPanelController panelController, QuickStatusBarHeader header, - QSFooter footer) { + QSFooter footer, FalsingManager falsingManager) { mQsPanelController = panelController; mHeader = header; mFooter = footer; mHeader.setCallback(mQsPanelCallback); mQsPanelController.setCallback(mQsPanelCallback); + mFalsingManager = falsingManager; } public void setHost(QSTileHost host) { @@ -273,6 +276,9 @@ public class QSDetail extends LinearLayout { final Intent settingsIntent = adapter.getSettingsIntent(); mDetailSettingsButton.setVisibility(settingsIntent != null ? VISIBLE : GONE); mDetailSettingsButton.setOnClickListener(v -> { + if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) { + return; + } Dependency.get(MetricsLogger.class).action(ACTION_QS_MORE_SETTINGS, adapter.getMetricsCategory()); mUiEventLogger.log(adapter.moreSettingsEvent()); @@ -280,6 +286,9 @@ public class QSDetail extends LinearLayout { .postStartActivityDismissingKeyguard(settingsIntent, 0); }); mDetailDoneButton.setOnClickListener(v -> { + if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) { + return; + } announceForAccessibility( mContext.getString(R.string.accessibility_desc_quick_settings)); if (!adapter.onDoneButtonClicked()) { @@ -301,13 +310,13 @@ public class QSDetail extends LinearLayout { mQsDetailHeaderSwitch.setVisibility(VISIBLE); handleToggleStateChanged(toggleState, adapter.getToggleEnabled()); mQsDetailHeader.setClickable(true); - mQsDetailHeader.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - boolean checked = !mQsDetailHeaderSwitch.isChecked(); - mQsDetailHeaderSwitch.setChecked(checked); - adapter.setToggleState(checked); + mQsDetailHeader.setOnClickListener(v -> { + if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) { + return; } + boolean checked = !mQsDetailHeaderSwitch.isChecked(); + mQsDetailHeaderSwitch.setChecked(checked); + adapter.setToggleState(checked); }); } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java index 0d91f29b5b2e..0a1e9d04fab0 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java @@ -39,6 +39,7 @@ import androidx.annotation.VisibleForTesting; import com.android.systemui.R; import com.android.systemui.animation.Interpolators; import com.android.systemui.media.MediaHost; +import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.QS; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.customize.QSCustomizerController; @@ -67,6 +68,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca private final Rect mQsBounds = new Rect(); private final StatusBarStateController mStatusBarStateController; + private final FalsingManager mFalsingManager; private boolean mQsExpanded; private boolean mHeaderAnimating; private boolean mStackScrollerOverscrolling; @@ -133,7 +135,8 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca StatusBarStateController statusBarStateController, CommandQueue commandQueue, QSDetailDisplayer qsDetailDisplayer, @Named(QS_PANEL) MediaHost qsMediaHost, @Named(QUICK_QS_PANEL) MediaHost qqsMediaHost, - QSFragmentComponent.Factory qsComponentFactory, FeatureFlags featureFlags) { + QSFragmentComponent.Factory qsComponentFactory, FeatureFlags featureFlags, + FalsingManager falsingManager) { mRemoteInputQuickSettingsDisabler = remoteInputQsDisabler; mInjectionInflater = injectionInflater; mCommandQueue = commandQueue; @@ -144,6 +147,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca commandQueue.observe(getLifecycle(), this); mHost = qsTileHost; mFeatureFlags = featureFlags; + mFalsingManager = falsingManager; mStatusBarStateController = statusBarStateController; } @@ -173,7 +177,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca mQSPanelScrollView.setOnScrollChangeListener( (v, scrollX, scrollY, oldScrollX, oldScrollY) -> { // Lazily update animators whenever the scrolling changes - mQSAnimator.onQsScrollingChanged(); + mQSAnimator.requestAnimatorUpdate(); mHeader.setExpandedScrollAmount(scrollY); if (mScrollListener != null) { mScrollListener.onQsPanelScrollChanged(scrollY); @@ -190,7 +194,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca mQSContainerImplController.init(); mContainer = mQSContainerImplController.getView(); - mQSDetail.setQsPanel(mQSPanelController, mHeader, mFooter); + mQSDetail.setQsPanel(mQSPanelController, mHeader, mFooter, mFalsingManager); mQSAnimator = qsFragmentComponent.getQSAnimator(); mQSCustomizerController = qsFragmentComponent.getQSCustomizerController(); @@ -215,6 +219,14 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca setQsExpansion(mLastQSExpansion, mLastHeaderTranslation); } }); + mQSPanelController.setUsingHorizontalLayoutChangeListener( + () -> { + // The hostview may be faded out in the horizontal layout. Let's make sure to + // reset the alpha when switching layouts. This is fine since the animator will + // update the alpha if it's not supposed to be 1.0f + mQSPanelController.getMediaHost().getHostView().setAlpha(1.0f); + mQSAnimator.requestAnimatorUpdate(); + }); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java index 7a0982688b49..4739a3f4c7d6 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java @@ -103,6 +103,9 @@ public abstract class QSPanelControllerBase<T extends QSPanel> extends ViewContr private boolean mUsingHorizontalLayout; + @Nullable + private Runnable mUsingHorizontalLayoutChangedListener; + protected QSPanelControllerBase( T view, QSTileHost host, @@ -135,6 +138,13 @@ public abstract class QSPanelControllerBase<T extends QSPanel> extends ViewContr mQSLogger.logAllTilesChangeListening(mView.isListening(), mView.getDumpableTag(), ""); } + /** + * @return the media host for this panel + */ + public MediaHost getMediaHost() { + return mMediaHost; + } + @Override protected void onViewAttached() { mQsTileRevealController = createTileRevealController(); @@ -303,6 +313,9 @@ public abstract class QSPanelControllerBase<T extends QSPanel> extends ViewContr mUsingHorizontalLayout = horizontal; mView.setUsingHorizontalLayout(mUsingHorizontalLayout, mMediaHost.getHostView(), force); updateMediaDisappearParameters(); + if (mUsingHorizontalLayoutChangedListener != null) { + mUsingHorizontalLayoutChangedListener.run(); + } return true; } return false; @@ -386,6 +399,13 @@ public abstract class QSPanelControllerBase<T extends QSPanel> extends ViewContr mMediaVisibilityChangedListener = listener; } + /** + * Add a listener when the horizontal layout changes + */ + public void setUsingHorizontalLayoutChangeListener(Runnable listener) { + mUsingHorizontalLayoutChangedListener = listener; + } + /** */ public static final class TileRecord extends QSPanel.Record { public QSTile tile; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java index 82b6c0c1805d..ab81ac1fd577 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java @@ -153,9 +153,25 @@ public class QuickAccessWalletTile extends QSTileImpl<QSTile.State> { }); } + @Nullable + private CharSequence getServiceLabelSafe() { + try { + return mController.getWalletClient().getServiceLabel(); + } catch (RuntimeException e) { + Log.e(TAG, "Failed to get the service label safely, recreating wallet client", e); + mController.reCreateWalletClient(); + try { + return mController.getWalletClient().getServiceLabel(); + } catch (RuntimeException e2) { + Log.e(TAG, "The QAW service label is broken.", e2); + return null; + } + } + } + @Override protected void handleUpdateState(State state, Object arg) { - CharSequence label = mController.getWalletClient().getServiceLabel(); + CharSequence label = getServiceLabelSafe(); state.label = label == null ? mLabel : label; state.contentDescription = state.label; Drawable tileIcon = mController.getWalletClient().getTileIcon(); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyToggleTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyToggleTile.java index f13576c2d4cc..bf72b7728232 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyToggleTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyToggleTile.java @@ -16,6 +16,8 @@ package com.android.systemui.qs.tiles; +import static android.hardware.SensorPrivacyManager.Sources.QS_TILE; + import android.content.Intent; import android.hardware.SensorPrivacyManager.Sensors.Sensor; import android.os.Handler; @@ -87,12 +89,12 @@ public abstract class SensorPrivacyToggleTile extends QSTileImpl<QSTile.BooleanS protected void handleClick(@Nullable View view) { if (mKeyguard.isMethodSecure() && mKeyguard.isShowing()) { mActivityStarter.postQSRunnableDismissingKeyguard(() -> { - mSensorPrivacyController.setSensorBlocked(getSensorId(), + mSensorPrivacyController.setSensorBlocked(QS_TILE, getSensorId(), !mSensorPrivacyController.isSensorBlocked(getSensorId())); }); return; } - mSensorPrivacyController.setSensorBlocked(getSensorId(), + mSensorPrivacyController.setSensorBlocked(QS_TILE, getSensorId(), !mSensorPrivacyController.isSensorBlocked(getSensorId())); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java index a9723341e787..04437ea14bb3 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java @@ -146,7 +146,7 @@ public class UserDetailView extends PseudoGridView { @Override public void onClick(View view) { - if (mFalsingManager.isFalseTap(FalsingManager.MODERATE_PENALTY)) { + if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) { return; } diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java index 53259435da02..da9d8882c091 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java +++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java @@ -110,6 +110,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.function.BiConsumer; +import java.util.function.Supplier; import javax.inject.Inject; @@ -172,55 +173,34 @@ public class OverviewProxyService extends CurrentUserTracker implements public ISystemUiProxy mSysUiProxy = new ISystemUiProxy.Stub() { @Override public void startScreenPinning(int taskId) { - if (!verifyCaller("startScreenPinning")) { - return; - } - final long token = Binder.clearCallingIdentity(); - try { - mHandler.post(() -> { + verifyCallerAndClearCallingIdentityPostMain("startScreenPinning", () -> mStatusBarOptionalLazy.ifPresent( statusBarLazy -> statusBarLazy.get().showScreenPinningRequest(taskId, - false /* allowCancel */)); - }); - } finally { - Binder.restoreCallingIdentity(token); - } + false /* allowCancel */))); } @Override public void stopScreenPinning() { - if (!verifyCaller("stopScreenPinning")) { - return; - } - final long token = Binder.clearCallingIdentity(); - try { - mHandler.post(() -> { - try { - ActivityTaskManager.getService().stopSystemLockTaskMode(); - } catch (RemoteException e) { - Log.e(TAG_OPS, "Failed to stop screen pinning"); - } - }); - } finally { - Binder.restoreCallingIdentity(token); - } + verifyCallerAndClearCallingIdentityPostMain("stopScreenPinning", () -> { + try { + ActivityTaskManager.getService().stopSystemLockTaskMode(); + } catch (RemoteException e) { + Log.e(TAG_OPS, "Failed to stop screen pinning"); + } + }); } // TODO: change the method signature to use (boolean inputFocusTransferStarted) @Override public void onStatusBarMotionEvent(MotionEvent event) { - if (!verifyCaller("onStatusBarMotionEvent")) { - return; - } - final long token = Binder.clearCallingIdentity(); - try { + verifyCallerAndClearCallingIdentity("onStatusBarMotionEvent", () -> { // TODO move this logic to message queue mStatusBarOptionalLazy.ifPresent(statusBarLazy -> { StatusBar statusBar = statusBarLazy.get(); if (event.getActionMasked() == ACTION_DOWN) { statusBar.getPanelController().startExpandLatencyTracking(); } - mHandler.post(()-> { + mHandler.post(() -> { int action = event.getActionMasked(); if (action == ACTION_DOWN) { mInputFocusTransferStarted = true; @@ -232,50 +212,38 @@ public class OverviewProxyService extends CurrentUserTracker implements } if (action == ACTION_UP || action == ACTION_CANCEL) { mInputFocusTransferStarted = false; + float velocity = (event.getY() - mInputFocusTransferStartY) + / (event.getEventTime() - mInputFocusTransferStartMillis); statusBar.onInputFocusTransfer(mInputFocusTransferStarted, action == ACTION_CANCEL, - (event.getY() - mInputFocusTransferStartY) - / (event.getEventTime() - mInputFocusTransferStartMillis)); + velocity); } event.recycle(); }); }); - } finally { - Binder.restoreCallingIdentity(token); - } + }); } @Override public void onBackPressed() throws RemoteException { - if (!verifyCaller("onBackPressed")) { - return; - } - final long token = Binder.clearCallingIdentity(); - try { - mHandler.post(() -> { - sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK); - sendEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK); + verifyCallerAndClearCallingIdentityPostMain("onBackPressed", () -> { + sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK); + sendEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK); - notifyBackAction(true, -1, -1, true, false); - }); - } finally { - Binder.restoreCallingIdentity(token); - } + notifyBackAction(true, -1, -1, true, false); + }); } @Override public void setHomeRotationEnabled(boolean enabled) { - if (!verifyCaller("setHomeRotationEnabled")) { - return; - } - final long token = Binder.clearCallingIdentity(); - try { - mHandler.post(() -> { - mHandler.post(() -> notifyHomeRotationEnabled(enabled)); - }); - } finally { - Binder.restoreCallingIdentity(token); - } + verifyCallerAndClearCallingIdentityPostMain("setHomeRotationEnabled", () -> + mHandler.post(() -> notifyHomeRotationEnabled(enabled))); + } + + @Override + public void notifyTaskbarStatus(boolean visible, boolean stashed) { + verifyCallerAndClearCallingIdentityPostMain("notifyTaskbarStatus", () -> + onTaskbarStatusUpdated(visible, stashed)); } private boolean sendEvent(int action, int code) { @@ -292,124 +260,74 @@ public class OverviewProxyService extends CurrentUserTracker implements @Override public void onOverviewShown(boolean fromHome) { - if (!verifyCaller("onOverviewShown")) { - return; - } - final long token = Binder.clearCallingIdentity(); - try { - mHandler.post(() -> { - for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) { - mConnectionCallbacks.get(i).onOverviewShown(fromHome); - } - }); - } finally { - Binder.restoreCallingIdentity(token); - } + verifyCallerAndClearCallingIdentityPostMain("onOverviewShown", () -> { + for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) { + mConnectionCallbacks.get(i).onOverviewShown(fromHome); + } + }); } @Override public Rect getNonMinimizedSplitScreenSecondaryBounds() { - if (!verifyCaller("getNonMinimizedSplitScreenSecondaryBounds")) { - return null; - } - final long token = Binder.clearCallingIdentity(); - try { - return mLegacySplitScreenOptional.map(splitScreen -> - splitScreen.getDividerView().getNonMinimizedSplitScreenSecondaryBounds()) - .orElse(null); - } finally { - Binder.restoreCallingIdentity(token); - } + return verifyCallerAndClearCallingIdentity( + "getNonMinimizedSplitScreenSecondaryBounds", + () -> mLegacySplitScreenOptional.map(splitScreen -> + splitScreen + .getDividerView() + .getNonMinimizedSplitScreenSecondaryBounds()) + .orElse(null) + ); } @Override public void setNavBarButtonAlpha(float alpha, boolean animate) { - if (!verifyCaller("setNavBarButtonAlpha")) { - return; - } - final long token = Binder.clearCallingIdentity(); - try { - mNavBarButtonAlpha = alpha; - mHandler.post(() -> notifyNavBarButtonAlphaChanged(alpha, animate)); - } finally { - Binder.restoreCallingIdentity(token); - } + verifyCallerAndClearCallingIdentityPostMain("setNavBarButtonAlpha", () -> + notifyNavBarButtonAlphaChanged(alpha, animate)); } @Override public void onAssistantProgress(@FloatRange(from = 0.0, to = 1.0) float progress) { - if (!verifyCaller("onAssistantProgress")) { - return; - } - final long token = Binder.clearCallingIdentity(); - try { - mHandler.post(() -> notifyAssistantProgress(progress)); - } finally { - Binder.restoreCallingIdentity(token); - } + verifyCallerAndClearCallingIdentityPostMain("onAssistantProgress", () -> + notifyAssistantProgress(progress)); } @Override public void onAssistantGestureCompletion(float velocity) { - if (!verifyCaller("onAssistantGestureCompletion")) { - return; - } - final long token = Binder.clearCallingIdentity(); - try { - mHandler.post(() -> notifyAssistantGestureCompletion(velocity)); - } finally { - Binder.restoreCallingIdentity(token); - } + verifyCallerAndClearCallingIdentityPostMain("onAssistantGestureCompletion", () -> + notifyAssistantGestureCompletion(velocity)); } @Override public void startAssistant(Bundle bundle) { - if (!verifyCaller("startAssistant")) { - return; - } - final long token = Binder.clearCallingIdentity(); - try { - mHandler.post(() -> notifyStartAssistant(bundle)); - } finally { - Binder.restoreCallingIdentity(token); - } + verifyCallerAndClearCallingIdentityPostMain("startAssistant", () -> + notifyStartAssistant(bundle)); } @Override public void notifyAccessibilityButtonClicked(int displayId) { - if (!verifyCaller("notifyAccessibilityButtonClicked")) { - return; - } - final long token = Binder.clearCallingIdentity(); - try { - AccessibilityManager.getInstance(mContext) - .notifyAccessibilityButtonClicked(displayId); - } finally { - Binder.restoreCallingIdentity(token); - } + verifyCallerAndClearCallingIdentity("notifyAccessibilityButtonClicked", () -> + AccessibilityManager.getInstance(mContext) + .notifyAccessibilityButtonClicked(displayId)); } @Override public void notifyAccessibilityButtonLongClicked() { - if (!verifyCaller("notifyAccessibilityButtonLongClicked")) { - return; - } - final long token = Binder.clearCallingIdentity(); - try { - final Intent intent = - new Intent(AccessibilityManager.ACTION_CHOOSE_ACCESSIBILITY_BUTTON); - final String chooserClassName = AccessibilityButtonChooserActivity.class.getName(); - intent.setClassName(CHOOSER_PACKAGE_NAME, chooserClassName); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); - mContext.startActivityAsUser(intent, UserHandle.CURRENT); - } finally { - Binder.restoreCallingIdentity(token); - } + verifyCallerAndClearCallingIdentity("notifyAccessibilityButtonLongClicked", + () -> { + final Intent intent = + new Intent(AccessibilityManager.ACTION_CHOOSE_ACCESSIBILITY_BUTTON); + final String chooserClassName = AccessibilityButtonChooserActivity + .class.getName(); + intent.setClassName(CHOOSER_PACKAGE_NAME, chooserClassName); + intent.addFlags( + Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); + mContext.startActivityAsUser(intent, UserHandle.CURRENT); + }); } @Override public void handleImageAsScreenshot(Bitmap screenImage, Rect locationInScreen, - Insets visibleInsets, int taskId) { + Insets visibleInsets, int taskId) { // Deprecated } @@ -421,43 +339,22 @@ public class OverviewProxyService extends CurrentUserTracker implements @Override public void notifySwipeToHomeFinished() { - if (!verifyCaller("notifySwipeToHomeFinished")) { - return; - } - final long token = Binder.clearCallingIdentity(); - try { - mPipOptional.ifPresent( - pip -> pip.setPinnedStackAnimationType( - PipAnimationController.ANIM_TYPE_ALPHA)); - } finally { - Binder.restoreCallingIdentity(token); - } + verifyCallerAndClearCallingIdentity("notifySwipeToHomeFinished", () -> + mPipOptional.ifPresent( + pip -> pip.setPinnedStackAnimationType( + PipAnimationController.ANIM_TYPE_ALPHA))); } @Override public void notifySwipeUpGestureStarted() { - if (!verifyCaller("notifySwipeUpGestureStarted")) { - return; - } - final long token = Binder.clearCallingIdentity(); - try { - mHandler.post(() -> notifySwipeUpGestureStartedInternal()); - } finally { - Binder.restoreCallingIdentity(token); - } + verifyCallerAndClearCallingIdentityPostMain("notifySwipeUpGestureStarted", () -> + notifySwipeUpGestureStartedInternal()); } @Override public void notifyPrioritizedRotation(@Surface.Rotation int rotation) { - if (!verifyCaller("notifyPrioritizedRotation")) { - return; - } - final long token = Binder.clearCallingIdentity(); - try { - mHandler.post(() -> notifyPrioritizedRotationInternal(rotation)); - } finally { - Binder.restoreCallingIdentity(token); - } + verifyCallerAndClearCallingIdentityPostMain("notifyPrioritizedRotation", () -> + notifyPrioritizedRotationInternal(rotation)); } @Override @@ -477,15 +374,8 @@ public class OverviewProxyService extends CurrentUserTracker implements @Override public void expandNotificationPanel() { - if (!verifyCaller("expandNotificationPanel")) { - return; - } - final long token = Binder.clearCallingIdentity(); - try { - mCommandQueue.handleSystemKey(KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN); - } finally { - Binder.restoreCallingIdentity(token); - } + verifyCallerAndClearCallingIdentity("expandNotificationPanel", + () -> mCommandQueue.handleSystemKey(KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN)); } private boolean verifyCaller(String reason) { @@ -497,6 +387,29 @@ public class OverviewProxyService extends CurrentUserTracker implements } return true; } + + private <T> T verifyCallerAndClearCallingIdentity(String reason, Supplier<T> supplier) { + if (!verifyCaller(reason)) { + return null; + } + final long token = Binder.clearCallingIdentity(); + try { + return supplier.get(); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + private void verifyCallerAndClearCallingIdentity(String reason, Runnable runnable) { + verifyCallerAndClearCallingIdentity(reason, () -> { + runnable.run(); + return null; + }); + } + + private void verifyCallerAndClearCallingIdentityPostMain(String reason, Runnable runnable) { + verifyCallerAndClearCallingIdentity(reason, () -> mHandler.post(runnable)); + } }; private final Runnable mDeferredConnectionCallback = () -> { @@ -883,6 +796,12 @@ public class OverviewProxyService extends CurrentUserTracker implements } } + private void onTaskbarStatusUpdated(boolean visible, boolean stashed) { + for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) { + mConnectionCallbacks.get(i).onTaskbarStatusUpdated(visible, stashed); + } + } + private void notifyConnectionChanged() { for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) { mConnectionCallbacks.get(i).onConnectionChanged(mOverviewProxy != null); @@ -1049,6 +968,7 @@ public class OverviewProxyService extends CurrentUserTracker implements /** Notify changes in the nav bar button alpha */ default void onNavBarButtonAlphaChanged(float alpha, boolean animate) {} default void onHomeRotationEnabled(boolean enabled) {} + default void onTaskbarStatusUpdated(boolean visible, boolean stashed) {} default void onSystemUiStateChanged(int sysuiStateFlags) {} default void onAssistantProgress(@FloatRange(from = 0.0, to = 1.0) float progress) {} default void onAssistantGestureCompletion(float velocity) {} diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ImageTileSet.java b/packages/SystemUI/src/com/android/systemui/screenshot/ImageTileSet.java index 51cc32ad39c1..356f67e7ea00 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ImageTileSet.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ImageTileSet.java @@ -24,7 +24,6 @@ import android.graphics.Region; import android.graphics.RenderNode; import android.graphics.drawable.Drawable; import android.os.Handler; -import android.util.Log; import androidx.annotation.UiThread; @@ -140,7 +139,6 @@ class ImageTileSet { * getHeight()). */ Bitmap toBitmap(Rect bounds) { - Log.d(TAG, "exporting with bounds: " + bounds); if (mTiles.isEmpty()) { return null; } diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java b/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java index cb6ac47c3cb3..0eaef72ae29b 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java @@ -63,7 +63,7 @@ import javax.inject.Inject; * and bottom before saving/sharing/editing. */ public class LongScreenshotActivity extends Activity { - private static final String TAG = "LongScreenshotActivity"; + private static final String TAG = LogConfig.logTag(LongScreenshotActivity.class); public static final String EXTRA_CAPTURE_RESPONSE = "capture-response"; private static final String KEY_SAVED_IMAGE_PATH = "saved-image-path"; @@ -112,7 +112,6 @@ public class LongScreenshotActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { - Log.d(TAG, "onCreate(savedInstanceState = " + savedInstanceState + ")"); super.onCreate(savedInstanceState); setContentView(R.layout.long_screenshot); @@ -154,9 +153,13 @@ public class LongScreenshotActivity extends Activity { @Override public void onStart() { - Log.d(TAG, "onStart"); super.onStart(); + if (mPreview.getDrawable() != null) { + // We already have an image, so no need to try to load again. + return; + } + if (mCacheLoadFuture != null) { Log.d(TAG, "mCacheLoadFuture != null"); final ListenableFuture<ImageLoader.Result> future = mCacheLoadFuture; @@ -187,7 +190,7 @@ public class LongScreenshotActivity extends Activity { } private void onLongScreenshotReceived(LongScreenshot longScreenshot) { - Log.d(TAG, "onLongScreenshotReceived(longScreenshot=" + longScreenshot + ")"); + Log.i(TAG, "Completed: " + longScreenshot); mLongScreenshot = longScreenshot; Drawable drawable = mLongScreenshot.getDrawable(); mPreview.setImageDrawable(drawable); @@ -242,7 +245,6 @@ public class LongScreenshotActivity extends Activity { } private void onCachedImageLoaded(ImageLoader.Result imageResult) { - Log.d(TAG, "onCachedImageLoaded(imageResult=" + imageResult + ")"); BitmapDrawable drawable = new BitmapDrawable(getResources(), imageResult.bitmap); mPreview.setImageDrawable(drawable); mPreview.setAlpha(1f); @@ -267,7 +269,6 @@ public class LongScreenshotActivity extends Activity { @Override protected void onSaveInstanceState(Bundle outState) { - Log.d(TAG, "onSaveInstanceState"); super.onSaveInstanceState(outState); if (mSavedImagePath != null) { outState.putString(KEY_SAVED_IMAGE_PATH, mSavedImagePath.getPath()); @@ -275,14 +276,7 @@ public class LongScreenshotActivity extends Activity { } @Override - protected void onPause() { - Log.d(TAG, "onPause"); - super.onPause(); - } - - @Override protected void onStop() { - Log.d(TAG, "onStop finishing=" + isFinishing()); super.onStop(); if (mTransitionStarted) { finish(); @@ -304,19 +298,12 @@ public class LongScreenshotActivity extends Activity { mCacheSaveFuture.cancel(true); } if (mSavedImagePath != null) { - Log.d(TAG, "Deleting " + mSavedImagePath); //noinspection ResultOfMethodCallIgnored mSavedImagePath.delete(); mSavedImagePath = null; } } - @Override - protected void onDestroy() { - Log.d(TAG, "onDestroy"); - super.onDestroy(); - } - private void setButtonsEnabled(boolean enabled) { mSave.setEnabled(enabled); mEdit.setEnabled(enabled); @@ -379,7 +366,6 @@ public class LongScreenshotActivity extends Activity { } private void startExport(PendingAction action) { - Log.d(TAG, "startExport(action = " + action + ")"); Drawable drawable = mPreview.getDrawable(); if (drawable == null) { Log.e(TAG, "No drawable, skipping export!"); diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java index 4c1f6a19b96c..6dc68746e3ec 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java @@ -43,7 +43,7 @@ import javax.inject.Inject; * Interaction controller between the UI and ScrollCaptureClient. */ public class ScrollCaptureController { - private static final String TAG = "ScrollCaptureController"; + private static final String TAG = LogConfig.logTag(ScrollCaptureController.class); private static final float MAX_PAGES_DEFAULT = 3f; private static final String SETTING_KEY_MAX_PAGES = "screenshot.scroll_max_pages"; @@ -90,7 +90,9 @@ public class ScrollCaptureController { /** Releases image resources from the screenshot. */ public void release() { - Log.d(TAG, "LongScreenshot :: release()"); + if (LogConfig.DEBUG_SCROLL) { + Log.d(TAG, "LongScreenshot :: release()"); + } mImageTileSet.clear(); mSession.release(); } @@ -153,15 +155,11 @@ public class ScrollCaptureController { * @return a future ImageTile set containing the result */ ListenableFuture<LongScreenshot> run(ScrollCaptureResponse response) { - Log.d(TAG, "run: " + response); return CallbackToFutureAdapter.getFuture(completer -> { - Log.d(TAG, "getFuture(ImageTileSet) "); mCaptureCompleter = completer; mBgExecutor.execute(() -> { - Log.d(TAG, "bgExecutor.execute"); float maxPages = Settings.Secure.getFloat(mContext.getContentResolver(), SETTING_KEY_MAX_PAGES, MAX_PAGES_DEFAULT); - Log.d(TAG, "client start, maxPages=" + maxPages); mSessionFuture = mClient.start(response, maxPages); mSessionFuture.addListener(this::onStartComplete, mContext.getMainExecutor()); }); @@ -172,21 +170,27 @@ public class ScrollCaptureController { private void onStartComplete() { try { mSession = mSessionFuture.get(); - Log.d(TAG, "got session " + mSession); + if (LogConfig.DEBUG_SCROLL) { + Log.d(TAG, "got session " + mSession); + } requestNextTile(0); } catch (InterruptedException | ExecutionException e) { // Failure to start, propagate to caller - Log.d(TAG, "session start failed!"); + Log.e(TAG, "session start failed!"); mCaptureCompleter.setException(e); } } private void requestNextTile(int topPx) { - Log.d(TAG, "requestNextTile: " + topPx); + if (LogConfig.DEBUG_SCROLL) { + Log.d(TAG, "requestNextTile: " + topPx); + } mTileFuture = mSession.requestTile(topPx); mTileFuture.addListener(() -> { try { - Log.d(TAG, "onCaptureResult"); + if (LogConfig.DEBUG_SCROLL) { + Log.d(TAG, "onCaptureResult"); + } onCaptureResult(mTileFuture.get()); } catch (InterruptedException | ExecutionException e) { Log.e(TAG, "requestTile failed!", e); @@ -196,14 +200,18 @@ public class ScrollCaptureController { } private void onCaptureResult(CaptureResult result) { - Log.d(TAG, "onCaptureResult: " + result + " scrolling " + (mScrollingUp ? "UP" : "DOWN") - + " finish on boundary: " + mFinishOnBoundary); + if (LogConfig.DEBUG_SCROLL) { + Log.d(TAG, "onCaptureResult: " + result + " scrolling " + (mScrollingUp ? "UP" : "DOWN") + + " finish on boundary: " + mFinishOnBoundary); + } boolean emptyResult = result.captured.height() == 0; if (emptyResult) { // Potentially reached a vertical boundary. Extend in the other direction. if (mFinishOnBoundary) { - Log.d(TAG, "Empty: finished!"); + if (LogConfig.DEBUG_SCROLL) { + Log.d(TAG, "Empty: finished!"); + } finishCapture(); return; } else { @@ -212,13 +220,17 @@ public class ScrollCaptureController { mImageTileSet.clear(); mFinishOnBoundary = true; mScrollingUp = !mScrollingUp; - Log.d(TAG, "Empty: cleared, switch direction to finish"); + if (LogConfig.DEBUG_SCROLL) { + Log.d(TAG, "Empty: cleared, switch direction to finish"); + } } } else { // Got a non-empty result, but may already have enough bitmap data now int expectedTiles = mImageTileSet.size() + 1; if (expectedTiles >= mSession.getMaxTiles()) { - Log.d(TAG, "Hit max tiles: finished"); + if (LogConfig.DEBUG_SCROLL) { + Log.d(TAG, "Hit max tiles: finished"); + } // If we ever hit the max tiles, we've got enough bitmap data to finish // (even if we weren't sure we'd finish on this pass). finishCapture(); @@ -229,7 +241,9 @@ public class ScrollCaptureController { // by IDEAL_PORTION_ABOVE. if (mImageTileSet.getHeight() + result.captured.height() >= mSession.getTargetHeight() * IDEAL_PORTION_ABOVE) { - Log.d(TAG, "Hit ideal portion above: clear and switch direction"); + if (LogConfig.DEBUG_SCROLL) { + Log.d(TAG, "Hit ideal portion above: clear and switch direction"); + } // We got enough above the start point, now see how far down it can go. mImageTileSet.clear(); mScrollingUp = false; @@ -241,20 +255,25 @@ public class ScrollCaptureController { if (!emptyResult) { mImageTileSet.addTile(new ImageTile(result.image, result.captured)); } - - Log.d(TAG, "bounds: " + mImageTileSet.getLeft() + "," + mImageTileSet.getTop() - + " - " + mImageTileSet.getRight() + "," + mImageTileSet.getBottom() - + " (" + mImageTileSet.getWidth() + "x" + mImageTileSet.getHeight() + ")"); + if (LogConfig.DEBUG_SCROLL) { + Log.d(TAG, "bounds: " + mImageTileSet.getLeft() + "," + mImageTileSet.getTop() + + " - " + mImageTileSet.getRight() + "," + mImageTileSet.getBottom() + + " (" + mImageTileSet.getWidth() + "x" + mImageTileSet.getHeight() + ")"); + } Rect gapBounds = mImageTileSet.getGaps(); if (!gapBounds.isEmpty()) { - Log.d(TAG, "Found gaps in tileset: " + gapBounds + ", requesting " + gapBounds.top); + if (LogConfig.DEBUG_SCROLL) { + Log.d(TAG, "Found gaps in tileset: " + gapBounds + ", requesting " + gapBounds.top); + } requestNextTile(gapBounds.top); return; } if (mImageTileSet.getHeight() >= mSession.getTargetHeight()) { - Log.d(TAG, "Target height reached."); + if (LogConfig.DEBUG_SCROLL) { + Log.d(TAG, "Target height reached."); + } finishCapture(); return; } @@ -275,10 +294,14 @@ public class ScrollCaptureController { } private void finishCapture() { - Log.d(TAG, "finishCapture()"); + if (LogConfig.DEBUG_SCROLL) { + Log.d(TAG, "finishCapture()"); + } mEndFuture = mSession.end(); mEndFuture.addListener(() -> { - Log.d(TAG, "endCapture completed"); + if (LogConfig.DEBUG_SCROLL) { + Log.d(TAG, "endCapture completed"); + } // Provide result to caller and complete the top-level future // Caller is responsible for releasing this resource (ImageReader/HardwareBuffers) mCaptureCompleter.set(new LongScreenshot(mSession, mImageTileSet)); diff --git a/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseStartedActivity.kt b/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseStartedActivity.kt index a79316d6f5a9..f0fb5ebf9e1d 100644 --- a/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseStartedActivity.kt +++ b/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseStartedActivity.kt @@ -17,12 +17,14 @@ package com.android.systemui.sensorprivacy import android.content.DialogInterface +import android.content.Intent import android.content.Intent.EXTRA_PACKAGE_NAME import android.content.pm.PackageManager import android.content.res.Resources import android.hardware.SensorPrivacyManager import android.hardware.SensorPrivacyManager.EXTRA_ALL_SENSORS import android.hardware.SensorPrivacyManager.EXTRA_SENSOR +import android.hardware.SensorPrivacyManager.Sources.DIALOG import android.os.Bundle import android.os.Handler import android.text.Html @@ -37,6 +39,10 @@ import com.android.systemui.statusbar.phone.KeyguardDismissUtil import com.android.systemui.statusbar.policy.IndividualSensorPrivacyController import com.android.systemui.statusbar.policy.KeyguardStateController import javax.inject.Inject +import com.android.internal.util.FrameworkStatsLog.PRIVACY_TOGGLE_DIALOG_INTERACTION +import com.android.internal.util.FrameworkStatsLog.PRIVACY_TOGGLE_DIALOG_INTERACTION__ACTION__ENABLE +import com.android.internal.util.FrameworkStatsLog.PRIVACY_TOGGLE_DIALOG_INTERACTION__ACTION__CANCEL +import com.android.internal.util.FrameworkStatsLog.write /** * Dialog to be shown on top of apps that are attempting to use a sensor (e.g. microphone) which is @@ -173,7 +179,7 @@ class SensorUseStartedActivity @Inject constructor( override fun onStart() { super.onStart() - sensorPrivacyController.suppressSensorPrivacyReminders(sensorUsePackageName, true) + setSuppressed(true) unsuppressImmediately = false } @@ -184,16 +190,25 @@ class SensorUseStartedActivity @Inject constructor( keyguardDismissUtil.executeWhenUnlocked({ bgHandler.postDelayed({ disableSensorPrivacy() + write(PRIVACY_TOGGLE_DIALOG_INTERACTION, + PRIVACY_TOGGLE_DIALOG_INTERACTION__ACTION__ENABLE, + sensorUsePackageName) }, UNLOCK_DELAY_MILLIS) false }, false, true) } else { disableSensorPrivacy() + write(PRIVACY_TOGGLE_DIALOG_INTERACTION, + PRIVACY_TOGGLE_DIALOG_INTERACTION__ACTION__ENABLE, + sensorUsePackageName) } } BUTTON_NEGATIVE -> { unsuppressImmediately = false + write(PRIVACY_TOGGLE_DIALOG_INTERACTION, + PRIVACY_TOGGLE_DIALOG_INTERACTION__ACTION__CANCEL, + sensorUsePackageName) } } @@ -204,12 +219,10 @@ class SensorUseStartedActivity @Inject constructor( super.onStop() if (unsuppressImmediately) { - sensorPrivacyController - .suppressSensorPrivacyReminders(sensorUsePackageName, false) + setSuppressed(false) } else { bgHandler.postDelayed({ - sensorPrivacyController - .suppressSensorPrivacyReminders(sensorUsePackageName, false) + setSuppressed(false) }, SUPPRESS_REMINDERS_REMOVAL_DELAY_MILLIS) } } @@ -223,14 +236,31 @@ class SensorUseStartedActivity @Inject constructor( // do not allow backing out } + override fun onNewIntent(intent: Intent?) { + setIntent(intent) + recreate() + } + private fun disableSensorPrivacy() { if (sensor == ALL_SENSORS) { - sensorPrivacyController.setSensorBlocked(MICROPHONE, false) - sensorPrivacyController.setSensorBlocked(CAMERA, false) + sensorPrivacyController.setSensorBlocked(DIALOG, MICROPHONE, false) + sensorPrivacyController.setSensorBlocked(DIALOG, CAMERA, false) } else { - sensorPrivacyController.setSensorBlocked(sensor, false) + sensorPrivacyController.setSensorBlocked(DIALOG, sensor, false) } unsuppressImmediately = true setResult(RESULT_OK) } + + private fun setSuppressed(suppressed: Boolean) { + if (sensor == ALL_SENSORS) { + sensorPrivacyController + .suppressSensorPrivacyReminders(MICROPHONE, suppressed) + sensorPrivacyController + .suppressSensorPrivacyReminders(CAMERA, suppressed) + } else { + sensorPrivacyController + .suppressSensorPrivacyReminders(sensor, suppressed) + } + } }
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/sensorprivacy/television/TvUnblockSensorActivity.java b/packages/SystemUI/src/com/android/systemui/sensorprivacy/television/TvUnblockSensorActivity.java index 9d101effa99f..8cd3632b65ba 100644 --- a/packages/SystemUI/src/com/android/systemui/sensorprivacy/television/TvUnblockSensorActivity.java +++ b/packages/SystemUI/src/com/android/systemui/sensorprivacy/television/TvUnblockSensorActivity.java @@ -18,6 +18,7 @@ package com.android.systemui.sensorprivacy.television; import static android.hardware.SensorPrivacyManager.Sensors.CAMERA; import static android.hardware.SensorPrivacyManager.Sensors.MICROPHONE; +import static android.hardware.SensorPrivacyManager.Sources.OTHER; import android.hardware.SensorPrivacyManager; import android.os.Bundle; @@ -119,10 +120,10 @@ public class TvUnblockSensorActivity extends TvBottomSheetActivity { com.android.internal.R.string.sensor_privacy_start_use_dialog_turn_on_button); unblockButton.setOnClickListener(v -> { if (mSensor == ALL_SENSORS) { - mSensorPrivacyController.setSensorBlocked(CAMERA, false); - mSensorPrivacyController.setSensorBlocked(MICROPHONE, false); + mSensorPrivacyController.setSensorBlocked(OTHER, CAMERA, false); + mSensorPrivacyController.setSensorBlocked(OTHER, MICROPHONE, false); } else { - mSensorPrivacyController.setSensorBlocked(mSensor, false); + mSensorPrivacyController.setSensorBlocked(OTHER, mSensor, false); } }); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java index 8e52b0da54ef..c7f8dcf87eff 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java @@ -50,6 +50,7 @@ import android.os.ParcelFileDescriptor; import android.util.Log; import android.util.Pair; import android.util.SparseArray; +import android.view.InsetsState; import android.view.InsetsState.InternalInsetsType; import android.view.WindowInsetsController.Appearance; import android.view.WindowInsetsController.Behavior; @@ -337,7 +338,7 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< */ default void onSystemBarAttributesChanged(int displayId, @Appearance int appearance, AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme, - @Behavior int behavior, boolean isFullscreen) { } + @Behavior int behavior, InsetsState requestedState, String packageName) { } /** * @see IStatusBar#showTransient(int, int[]). @@ -996,7 +997,7 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< @Override public void onSystemBarAttributesChanged(int displayId, @Appearance int appearance, AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme, - @Behavior int behavior, boolean isFullscreen) { + @Behavior int behavior, InsetsState requestedState, String packageName) { synchronized (mLock) { SomeArgs args = SomeArgs.obtain(); args.argi1 = displayId; @@ -1004,7 +1005,8 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< args.argi3 = navbarColorManagedByIme ? 1 : 0; args.arg1 = appearanceRegions; args.argi4 = behavior; - args.argi5 = isFullscreen ? 1 : 0; + args.arg2 = requestedState; + args.arg3 = packageName; mHandler.obtainMessage(MSG_SYSTEM_BAR_CHANGED, args).sendToTarget(); } } @@ -1387,7 +1389,7 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< for (int i = 0; i < mCallbacks.size(); i++) { mCallbacks.get(i).onSystemBarAttributesChanged(args.argi1, args.argi2, (AppearanceRegion[]) args.arg1, args.argi3 == 1, args.argi4, - args.argi5 == 1); + (InsetsState) args.arg2, (String) args.arg3); } args.recycle(); break; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java index 5afdc38d739a..44399a126624 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java @@ -597,8 +597,8 @@ public class KeyguardIndicationController implements KeyguardStateController.Cal if (mDozing && !TextUtils.isEmpty(mTransientIndication)) { // Make sure this doesn't get stuck and burns in. Acquire wakelock until its cleared. mWakeLock.setAcquired(true); - hideTransientIndicationDelayed(BaseKeyguardCallback.HIDE_DELAY_MS); } + hideTransientIndicationDelayed(BaseKeyguardCallback.HIDE_DELAY_MS); updateIndication(false); } @@ -797,12 +797,15 @@ public class KeyguardIndicationController implements KeyguardStateController.Cal } if (mStatusBarKeyguardViewManager.isBouncerShowing()) { - String message = mContext.getString(R.string.keyguard_retry); - mStatusBarKeyguardViewManager.showBouncerMessage(message, mInitialTextColorState); + if (mStatusBarKeyguardViewManager.isShowingAlternateAuth()) { + return; // udfps affordance is highlighted, no need to surface face auth error + } else { + String message = mContext.getString(R.string.keyguard_retry); + mStatusBarKeyguardViewManager.showBouncerMessage(message, mInitialTextColorState); + } } else if (mKeyguardUpdateMonitor.isScreenOn()) { showTransientIndication(mContext.getString(R.string.keyguard_unlock), false /* isError */, true /* hideOnScreenOff */); - hideTransientIndicationDelayed(BaseKeyguardCallback.HIDE_DELAY_MS); } } @@ -862,7 +865,6 @@ public class KeyguardIndicationController implements KeyguardStateController.Cal if (mDozing) { if (!wasPluggedIn && mPowerPluggedIn) { showTransientIndication(computePowerIndication()); - hideTransientIndicationDelayed(HIDE_DELAY_MS); } else if (wasPluggedIn && !mPowerPluggedIn) { hideTransientIndication(); } @@ -882,23 +884,19 @@ public class KeyguardIndicationController implements KeyguardStateController.Cal return; } - if (biometricSourceType == BiometricSourceType.FACE - && shouldSuppressFaceMsgAndShowTryFingerprintMsg()) { - // suggest trying fingerprint - showTransientIndication(R.string.keyguard_try_fingerprint); - return; - } - boolean showSwipeToUnlock = msgId == KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_RECOGNIZED; if (mStatusBarKeyguardViewManager.isBouncerShowing()) { mStatusBarKeyguardViewManager.showBouncerMessage(helpString, mInitialTextColorState); } else if (mKeyguardUpdateMonitor.isScreenOn()) { - showTransientIndication(helpString, false /* isError */, showSwipeToUnlock); - if (!showSwipeToUnlock) { - hideTransientIndicationDelayed(TRANSIENT_BIOMETRIC_ERROR_TIMEOUT); + if (biometricSourceType == BiometricSourceType.FACE + && shouldSuppressFaceMsgAndShowTryFingerprintMsg()) { + // suggest trying fingerprint + showTransientIndication(R.string.keyguard_try_fingerprint); + return; } + showTransientIndication(helpString, false /* isError */, showSwipeToUnlock); } if (showSwipeToUnlock) { mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SWIPE_UP_TO_UNLOCK), @@ -913,7 +911,9 @@ public class KeyguardIndicationController implements KeyguardStateController.Cal return; } if (biometricSourceType == BiometricSourceType.FACE - && shouldSuppressFaceMsgAndShowTryFingerprintMsg()) { + && shouldSuppressFaceMsgAndShowTryFingerprintMsg() + && !mStatusBarKeyguardViewManager.isBouncerShowing() + && mKeyguardUpdateMonitor.isScreenOn()) { // suggest trying fingerprint showTransientIndication(R.string.keyguard_try_fingerprint); return; @@ -926,6 +926,11 @@ public class KeyguardIndicationController implements KeyguardStateController.Cal && mKeyguardUpdateMonitor.isFingerprintDetectionRunning()) { // suggest trying fingerprint showTransientIndication(R.string.keyguard_try_fingerprint); + } else if (mStatusBarKeyguardViewManager.isShowingAlternateAuth()) { + mStatusBarKeyguardViewManager.showBouncerMessage( + mContext.getResources().getString(R.string.keyguard_try_fingerprint), + mInitialTextColorState + ); } else { // suggest swiping up to unlock (try face auth again or swipe up to bouncer) showSwipeUpToUnlock(); @@ -935,8 +940,6 @@ public class KeyguardIndicationController implements KeyguardStateController.Cal } else if (mKeyguardUpdateMonitor.isScreenOn()) { showTransientIndication(errString, /* isError */ true, /* hideOnScreenOff */ true); - // We want to keep this message around in case the screen was off - hideTransientIndicationDelayed(HIDE_DELAY_MS); } else { mMessageToShowOnScreenOn = errString; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java index baac2549055f..cd5cce4f3ee7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java @@ -367,6 +367,7 @@ public class NotificationShelf extends ActivatableNotificationView implements && !mHostLayoutController.isViewAffectedBySwipe(anv) && !isUnlockedHeadsUp && !isHunGoingToShade + && !anv.isAboveShelf() && !mAmbientState.isPulsing() && !mAmbientState.isDozing(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java index a00d01427ebc..5302188ccb31 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java @@ -416,10 +416,12 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi return mIcon.icon; } - private Drawable getIcon(StatusBarIcon icon) { - Context notifContext = mNotification != null ? - mNotification.getPackageContext(getContext()) : getContext(); - return getIcon(getContext(), notifContext, icon); + Drawable getIcon(StatusBarIcon icon) { + Context notifContext = getContext(); + if (mNotification != null) { + notifContext = mNotification.getPackageContext(getContext()); + } + return getIcon(getContext(), notifContext != null ? notifContext : getContext(), icon); } /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java index 0725bf961e13..d4f5bd241c6b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java @@ -16,6 +16,10 @@ package com.android.systemui.statusbar; +import static android.view.InsetsState.ITYPE_NAVIGATION_BAR; +import static android.view.InsetsState.ITYPE_STATUS_BAR; +import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS; + import static com.android.internal.jank.InteractionJankMonitor.CUJ_LOCKSCREEN_TRANSITION_FROM_AOD; import static com.android.internal.jank.InteractionJankMonitor.CUJ_LOCKSCREEN_TRANSITION_TO_AOD; @@ -23,10 +27,16 @@ import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; +import android.os.SystemProperties; import android.text.format.DateFormat; import android.util.FloatProperty; import android.util.Log; +import android.view.InsetsFlags; +import android.view.InsetsState; import android.view.View; +import android.view.ViewDebug; +import android.view.WindowInsetsController.Appearance; +import android.view.WindowInsetsController.Behavior; import android.view.animation.Interpolator; import androidx.annotation.NonNull; @@ -56,6 +66,9 @@ import javax.inject.Inject; public class StatusBarStateControllerImpl implements SysuiStatusBarStateController, CallbackController<StateListener>, Dumpable { private static final String TAG = "SbStateController"; + private static final boolean DEBUG_IMMERSIVE_APPS = + SystemProperties.getBoolean("persist.debug.immersive_apps", false); + // Must be a power of 2 private static final int HISTORY_SIZE = 32; @@ -420,7 +433,10 @@ public class StatusBarStateControllerImpl implements SysuiStatusBarStateControll } @Override - public void setFullscreenState(boolean isFullscreen) { + public void setSystemBarAttributes(@Appearance int appearance, @Behavior int behavior, + InsetsState requestedState, String packageName) { + boolean isFullscreen = !requestedState.getSourceOrDefaultVisibility(ITYPE_STATUS_BAR) + || !requestedState.getSourceOrDefaultVisibility(ITYPE_NAVIGATION_BAR); if (mIsFullscreen != isFullscreen) { mIsFullscreen = isFullscreen; synchronized (mListeners) { @@ -429,6 +445,19 @@ public class StatusBarStateControllerImpl implements SysuiStatusBarStateControll } } } + + // TODO (b/190543382): Finish the logging logic. + // This section can be removed if we don't need to print it on logcat. + if (DEBUG_IMMERSIVE_APPS) { + boolean dim = (appearance & APPEARANCE_LOW_PROFILE_BARS) != 0; + String behaviorName = ViewDebug.flagsToString(InsetsFlags.class, "behavior", behavior); + String requestedVisibilityString = requestedState.toSourceVisibilityString(); + if (requestedVisibilityString.isEmpty()) { + requestedVisibilityString = "none"; + } + Log.d(TAG, packageName + " dim=" + dim + " behavior=" + behaviorName + + " requested visibilities: " + requestedVisibilityString); + } } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java b/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java index 25200501a916..0bbae2aa2955 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java @@ -19,7 +19,10 @@ package com.android.systemui.statusbar; import static java.lang.annotation.RetentionPolicy.SOURCE; import android.annotation.IntDef; +import android.view.InsetsState; import android.view.View; +import android.view.WindowInsetsController.Appearance; +import android.view.WindowInsetsController.Behavior; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.phone.StatusBar; @@ -155,9 +158,10 @@ public interface SysuiStatusBarStateController extends StatusBarStateController boolean isKeyguardRequested(); /** - * Set the fullscreen state + * Set the system bar attributes */ - void setFullscreenState(boolean isFullscreen); + void setSystemBarAttributes(@Appearance int appearance, @Behavior int behavior, + InsetsState requestedState, String packageName); /** * Set pulsing diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java index a32b7e3b2836..6964838e7e41 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java @@ -70,6 +70,7 @@ import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.notification.row.OnUserInteractionCallback; import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager; import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm; +import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.ShadeController; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.policy.HeadsUpManager; @@ -93,6 +94,10 @@ public interface NotificationsModule { StackScrollAlgorithm.SectionProvider bindSectionProvider( NotificationSectionsManager impl); + @Binds + StackScrollAlgorithm.BypassController bindBypassController( + KeyguardBypassController impl); + /** Provides an instance of {@link NotificationEntryManager} */ @SysUISingleton @Provides diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapper.java index 222735aeb35a..4c9c2f95b35c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapper.java @@ -47,10 +47,6 @@ public class NotificationCustomViewWrapper extends NotificationViewWrapper { public void onContentUpdated(ExpandableNotificationRow row) { super.onContentUpdated(row); - // Custom views will most likely use just white or black as their text color. - // We need to scan through and replace these colors by Material NEXT colors. - ensureThemeOnChildren(mView); - // Let's invert the notification colors when we're in night mode and // the notification background isn't colorized. if (needsInversion(mBackgroundColor, mView)) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationDecoratedCustomViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationDecoratedCustomViewWrapper.java index d21ae13a1e01..8c6fa023d92b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationDecoratedCustomViewWrapper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationDecoratedCustomViewWrapper.java @@ -62,10 +62,6 @@ public class NotificationDecoratedCustomViewWrapper extends NotificationTemplate public void onContentUpdated(ExpandableNotificationRow row) { mWrappedView = getWrappedCustomView(mView); - // Custom views will most likely use just white or black as their text color. - // We need to scan through and replace these colors by Material NEXT colors. - ensureThemeOnChildren(mWrappedView); - if (needsInversion(resolveBackgroundColor(), mWrappedView)) { invertViewLuminosity(mWrappedView); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java index 74abd38ec398..76301917b458 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java @@ -30,7 +30,6 @@ import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.os.Build; import android.util.Pair; -import android.view.ContextThemeWrapper; import android.view.NotificationHeaderView; import android.view.View; import android.view.ViewGroup; @@ -41,7 +40,6 @@ import com.android.internal.graphics.ColorUtils; import com.android.internal.util.ContrastColorUtil; import com.android.internal.widget.CachingIconView; import com.android.settingslib.Utils; -import com.android.systemui.R; import com.android.systemui.statusbar.CrossFadeHelper; import com.android.systemui.statusbar.TransformableView; import com.android.systemui.statusbar.notification.TransformState; @@ -58,11 +56,6 @@ public abstract class NotificationViewWrapper implements TransformableView { private final Rect mTmpRect = new Rect(); protected int mBackgroundColor = 0; - private int mMaterialTextColorPrimary; - private int mMaterialTextColorSecondary; - private int mThemedTextColorPrimary; - private int mThemedTextColorSecondary; - private boolean mAdjustTheme; public static NotificationViewWrapper wrap(Context ctx, View v, ExpandableNotificationRow row) { if (v.getId() == com.android.internal.R.id.status_bar_latest_event_content) { @@ -98,8 +91,6 @@ public abstract class NotificationViewWrapper implements TransformableView { mView = view; mRow = row; onReinflated(); - mAdjustTheme = ctx.getResources().getBoolean( - R.bool.config_adjustThemeOnNotificationCustomViews); } /** @@ -124,22 +115,6 @@ public abstract class NotificationViewWrapper implements TransformableView { mBackgroundColor = backgroundColor; mView.setBackground(new ColorDrawable(Color.TRANSPARENT)); } - - Context materialTitleContext = new ContextThemeWrapper(mView.getContext(), - com.android.internal.R.style.TextAppearance_Material_Notification_Title); - mMaterialTextColorPrimary = Utils.getColorAttr(materialTitleContext, - com.android.internal.R.attr.textColor).getDefaultColor(); - Context materialContext = new ContextThemeWrapper(mView.getContext(), - com.android.internal.R.style.TextAppearance_Material_Notification); - mMaterialTextColorSecondary = Utils.getColorAttr(materialContext, - com.android.internal.R.attr.textColor).getDefaultColor(); - - Context themedContext = new ContextThemeWrapper(mView.getContext(), - com.android.internal.R.style.Theme_DeviceDefault_DayNight); - mThemedTextColorPrimary = Utils.getColorAttr(themedContext, - com.android.internal.R.attr.textColorPrimary).getDefaultColor(); - mThemedTextColorSecondary = Utils.getColorAttr(themedContext, - com.android.internal.R.attr.textColorSecondary).getDefaultColor(); } protected boolean needsInversion(int defaultBackgroundColor, View view) { @@ -217,39 +192,6 @@ public abstract class NotificationViewWrapper implements TransformableView { return false; } - protected void ensureThemeOnChildren(View rootView) { - if (!mAdjustTheme || mView == null || rootView == null) { - return; - } - - // Notifications with custom backgrounds should not be adjusted - if (mBackgroundColor != Color.TRANSPARENT - || getBackgroundColor(mView) != Color.TRANSPARENT - || getBackgroundColor(rootView) != Color.TRANSPARENT) { - return; - } - - // Now let's check if there's unprotected text somewhere, and apply the theme if we find it. - processTextColorRecursive(rootView); - } - - private void processTextColorRecursive(View view) { - if (view instanceof TextView) { - TextView textView = (TextView) view; - int foreground = textView.getCurrentTextColor(); - if (foreground == mMaterialTextColorPrimary) { - textView.setTextColor(mThemedTextColorPrimary); - } else if (foreground == mMaterialTextColorSecondary) { - textView.setTextColor(mThemedTextColorSecondary); - } - } else if (view instanceof ViewGroup) { - ViewGroup viewGroup = (ViewGroup) view; - for (int i = 0; i < viewGroup.getChildCount(); i++) { - processTextColorRecursive(viewGroup.getChildAt(i)); - } - } - } - protected int getBackgroundColor(View view) { if (view == null) { return Color.TRANSPARENT; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java index 197920f7be19..9846b28ba5f9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java @@ -29,6 +29,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.ExpandableView; +import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm.BypassController; import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm.SectionProvider; import javax.inject.Inject; @@ -43,6 +44,7 @@ public class AmbientState { private static final boolean NOTIFICATIONS_HAVE_SHADOWS = false; private final SectionProvider mSectionProvider; + private final BypassController mBypassController; private int mScrollY; private boolean mDimmed; private ActivatableNotificationView mActivatedChild; @@ -152,14 +154,25 @@ public class AmbientState { return mStackHeight; } + /** + * @return Height of notifications panel, with the animation from pulseHeight accounted for. + */ + // TODO(b/192348384): move this logic to getStackHeight, and remove this and getInnerHeight + public float getPulseStackHeight() { + float pulseHeight = Math.min(mPulseHeight, mStackHeight); + return MathUtils.lerp(mStackHeight, pulseHeight, mDozeAmount); + } + /** Tracks the state from AlertingNotificationManager#hasNotifications() */ private boolean mHasAlertEntries; @Inject public AmbientState( Context context, - @NonNull SectionProvider sectionProvider) { + @NonNull SectionProvider sectionProvider, + @NonNull BypassController bypassController) { mSectionProvider = sectionProvider; + mBypassController = bypassController; reload(context); } @@ -297,6 +310,13 @@ public class AmbientState { } } + /** + * Is bypass currently enabled? + */ + public boolean isBypassEnabled() { + return mBypassController.isBypassEnabled(); + } + public float getOverScrollAmount(boolean top) { return top ? mOverScrollTopAmount : mOverScrollBottomAmount; } 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 e60ec334049f..2673ebdd1f6a 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 @@ -89,7 +89,6 @@ import com.android.systemui.statusbar.RemoteInputController; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.notification.ExpandAnimationParameters; import com.android.systemui.statusbar.notification.FakeShadowView; -import com.android.systemui.statusbar.notification.NotificationActivityStarter; import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorController; import com.android.systemui.statusbar.notification.NotificationUtils; import com.android.systemui.statusbar.notification.ShadeViewRefactor; @@ -155,7 +154,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable * gap is drawn between them). In this case we don't want to round their corners. */ private static final int DISTANCE_BETWEEN_ADJACENT_SECTIONS_PX = 1; - private KeyguardBypassEnabledProvider mKeyguardBypassEnabledProvider; + private boolean mKeyguardBypassEnabled; private ExpandHelper mExpandHelper; private NotificationSwipeHelper mSwipeHelper; @@ -212,7 +211,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable private GroupMembershipManager mGroupMembershipManager; private GroupExpansionManager mGroupExpansionManager; - private NotificationActivityStarter mNotificationActivityStarter; private HashSet<ExpandableView> mChildrenToAddAnimated = new HashSet<>(); private ArrayList<View> mAddedHeadsUpChildren = new ArrayList<>(); private ArrayList<ExpandableView> mChildrenToRemoveAnimated = new ArrayList<>(); @@ -564,6 +562,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable } }; + @Nullable + private OnClickListener mManageButtonClickListener; + @Inject public NotificationStackScrollLayout( @Named(VIEW_CONTEXT) Context context, @@ -650,12 +651,20 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable } /** + * Sets whether keyguard bypass is enabled. If true, this layout will be rendered in bypass + * mode when it is on the keyguard. + */ + public void setKeyguardBypassEnabled(boolean isEnabled) { + mKeyguardBypassEnabled = isEnabled; + } + + /** * @return the height at which we will wake up when pulsing */ public float getWakeUpHeight() { ExpandableView firstChild = getFirstChildWithBackground(); if (firstChild != null) { - if (mKeyguardBypassEnabledProvider.getBypassEnabled()) { + if (mKeyguardBypassEnabled) { return firstChild.getHeadsUpHeightWithoutHeader(); } else { return firstChild.getCollapsedHeight(); @@ -681,8 +690,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable boolean showDismissView = mClearAllEnabled && mController.hasActiveClearableNotifications(ROWS_ALL); RemoteInputController remoteInputController = mRemoteInputManager.getController(); - boolean showFooterView = (showDismissView || mController.hasActiveNotifications()) - && mEmptyShadeView.getVisibility() == GONE + boolean showFooterView = (showDismissView || getVisibleNotificationCount() > 0) && mStatusBarState != StatusBarState.KEYGUARD && !mUnlockedScreenOffAnimationController.isScreenOffAnimationPlaying() && (remoteInputController == null || !remoteInputController.isRemoteInputActive()); @@ -784,7 +792,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable } } boolean shouldDrawBackground; - if (mKeyguardBypassEnabledProvider.getBypassEnabled() && onKeyguard()) { + if (mKeyguardBypassEnabled && onKeyguard()) { shouldDrawBackground = isPulseExpanding(); } else { shouldDrawBackground = !mAmbientState.isDozing() || anySectionHasVisibleChild; @@ -899,15 +907,12 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable } private void reinitView() { - initView(getContext(), mKeyguardBypassEnabledProvider, mSwipeHelper); + initView(getContext(), mSwipeHelper); } @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) - void initView(Context context, - KeyguardBypassEnabledProvider keyguardBypassEnabledProvider, - NotificationSwipeHelper swipeHelper) { + void initView(Context context, NotificationSwipeHelper swipeHelper) { mScroller = new OverScroller(getContext()); - mKeyguardBypassEnabledProvider = keyguardBypassEnabledProvider; mSwipeHelper = swipeHelper; setDescendantFocusability(FOCUS_AFTER_DESCENDANTS); @@ -1347,7 +1352,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable private void notifyAppearChangedListeners() { float appear; float expandAmount; - if (mKeyguardBypassEnabledProvider.getBypassEnabled() && onKeyguard()) { + if (mKeyguardBypassEnabled && onKeyguard()) { appear = calculateAppearFractionBypass(); expandAmount = getPulseHeight(); } else { @@ -2385,8 +2390,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable minTopPosition = firstVisibleSection.getBounds().top; } boolean shiftPulsingWithFirst = mNumHeadsUp <= 1 - && (mAmbientState.isDozing() - || (mKeyguardBypassEnabledProvider.getBypassEnabled() && onKeyguard)); + && (mAmbientState.isDozing() || (mKeyguardBypassEnabled && onKeyguard)); for (NotificationSection section : mSections) { int minBottomPosition = minTopPosition; if (section == lastSection) { @@ -2529,7 +2533,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable } else { mTopPaddingOverflow = 0; } - setTopPadding(topPadding, animate && !mKeyguardBypassEnabledProvider.getBypassEnabled()); + setTopPadding(topPadding, animate && !mKeyguardBypassEnabled); setExpandedHeight(mExpandedHeight); } @@ -3093,7 +3097,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable boolean performDisappearAnimation = !mIsExpanded // Only animate if we still have pinned heads up, otherwise we just have the // regular collapse animation of the lock screen - || (mKeyguardBypassEnabledProvider.getBypassEnabled() && onKeyguard() + || (mKeyguardBypassEnabled && onKeyguard() && mInHeadsUpPinnedMode); if (performDisappearAnimation && !isHeadsUp) { type = row.wasJustClicked() @@ -4316,7 +4320,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable // Since we are clipping to the outline we need to make sure that the shadows aren't // clipped when pulsing float ownTranslationZ = 0; - if (mKeyguardBypassEnabledProvider.getBypassEnabled() && mAmbientState.isHiddenAtAll()) { + if (mKeyguardBypassEnabled && mAmbientState.isHiddenAtAll()) { ExpandableView firstChildNotGone = getFirstChildNotGone(); if (firstChildNotGone != null && firstChildNotGone.showingPulsing()) { ownTranslationZ = firstChildNotGone.getTranslationZ(); @@ -4358,6 +4362,14 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable return -1; } + /** + * Returns whether or not a History button is shown in the footer. If there is no footer, then + * this will return false. + **/ + public boolean isHistoryShown() { + return mFooterView != null && mFooterView.isHistoryShown(); + } + @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) void setFooterView(@NonNull FooterView footerView) { int index = -1; @@ -4367,6 +4379,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable } mFooterView = footerView; addView(mFooterView, index); + if (mManageButtonClickListener != null) { + mFooterView.setManageButtonClickListener(mManageButtonClickListener); + } } @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) @@ -5070,9 +5085,12 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable } } - public void setNotificationActivityStarter( - NotificationActivityStarter notificationActivityStarter) { - mNotificationActivityStarter = notificationActivityStarter; + /** Register a {@link View.OnClickListener} to be invoked when the Manage button is clicked. */ + public void setManageButtonClickListener(@Nullable OnClickListener listener) { + mManageButtonClickListener = listener; + if (mFooterView != null) { + mFooterView.setManageButtonClickListener(mManageButtonClickListener); + } } @VisibleForTesting @@ -5086,9 +5104,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable } clearNotifications(ROWS_ALL, true /* closeShade */); }); - footerView.setManageButtonClickListener(v -> { - mNotificationActivityStarter.startHistoryIntent(v, mFooterView.isHistoryShown()); - }); setFooterView(footerView); } @@ -5139,7 +5154,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable */ public float setPulseHeight(float height) { mAmbientState.setPulseHeight(height); - if (mKeyguardBypassEnabledProvider.getBypassEnabled()) { + if (mKeyguardBypassEnabled) { notifyAppearChangedListeners(); } requestChildrenUpdate(); @@ -6070,10 +6085,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable /** Only rows where entry.isHighPriority() is false. */ public static final int ROWS_GENTLE = 2; - interface KeyguardBypassEnabledProvider { - boolean getBypassEnabled(); - } - interface DismissListener { void onDismiss(@SelectedRows int selectedRows); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java index a92682a76a9c..428a8407cc53 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java @@ -48,6 +48,8 @@ import android.view.View; import android.view.ViewGroup; import android.view.WindowInsets; +import androidx.annotation.Nullable; + import com.android.internal.annotations.VisibleForTesting; import com.android.internal.colorextraction.ColorExtractor; import com.android.internal.jank.InteractionJankMonitor; @@ -184,6 +186,9 @@ public class NotificationStackScrollLayoutController { private final NotificationListContainerImpl mNotificationListContainer = new NotificationListContainerImpl(); + @Nullable + private NotificationActivityStarter mNotificationActivityStarter; + private ColorExtractor.OnColorsChangedListener mOnColorsChangedListener; /** @@ -708,8 +713,15 @@ public class NotificationStackScrollLayoutController { }); } - mView.initView(mView.getContext(), mKeyguardBypassController::getBypassEnabled, - mSwipeHelper); + mView.initView(mView.getContext(), mSwipeHelper); + mView.setKeyguardBypassEnabled(mKeyguardBypassController.getBypassEnabled()); + mKeyguardBypassController + .registerOnBypassStateChangedListener(mView::setKeyguardBypassEnabled); + mView.setManageButtonClickListener(v -> { + if (mNotificationActivityStarter != null) { + mNotificationActivityStarter.startHistoryIntent(v, mView.isHistoryShown()); + } + }); mHeadsUpManager.addListener(mOnHeadsUpChangedListener); mHeadsUpManager.setAnimationStateHandler(mView::setHeadsUpGoingAwayAnimationsAllowed); @@ -1470,6 +1482,10 @@ public class NotificationStackScrollLayoutController { mView.animateNextTopPaddingChange(); } + public void setNotificationActivityStarter(NotificationActivityStarter activityStarter) { + mNotificationActivityStarter = activityStarter; + } + /** * Enum for UiEvent logged from this class */ @@ -1541,7 +1557,8 @@ public class NotificationStackScrollLayoutController { @Override public void setNotificationActivityStarter( NotificationActivityStarter notificationActivityStarter) { - mView.setNotificationActivityStarter(notificationActivityStarter); + NotificationStackScrollLayoutController.this + .setNotificationActivityStarter(notificationActivityStarter); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java index 3fc8b8d9aef1..e65038b32bf0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java @@ -421,10 +421,20 @@ public class StackScrollAlgorithm { // When pulsing (incoming notification on AOD), innerHeight is 0; clamp all // to shelf start, thereby hiding all notifications (except the first one, which // we later unhide in updatePulsingState) - final int stackBottom = - !ambientState.isShadeExpanded() || ambientState.isDozing() - ? ambientState.getInnerHeight() - : (int) ambientState.getStackHeight(); + // TODO(b/192348384): merge InnerHeight with StackHeight + final int stackBottom; + if (ambientState.isBypassEnabled()) { + // We want to use the stackHeight when pulse expanding, since the animation + // isn't currently optimized if the pulseHeight is continuously changing + // Let's improve this when we're merging the heights above + stackBottom = ambientState.isPulseExpanding() + ? (int) ambientState.getStackHeight() + : ambientState.getInnerHeight(); + } else { + stackBottom = !ambientState.isShadeExpanded() || ambientState.isDozing() + ? ambientState.getInnerHeight() + : (int) ambientState.getPulseStackHeight(); + } final int shelfStart = stackBottom - ambientState.getShelf().getIntrinsicHeight(); viewState.yTranslation = Math.min(viewState.yTranslation, shelfStart); @@ -742,4 +752,14 @@ public class StackScrollAlgorithm { */ boolean beginsSection(@NonNull View view, @Nullable View previous); } + + /** + * Interface for telling the StackScrollAlgorithm information about the bypass state + */ + public interface BypassController { + /** + * True if bypass is enabled. Note that this is always false if face auth is not enabled. + */ + boolean isBypassEnabled(); + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java index 20e6f60c9b17..6d5c53609f81 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java @@ -39,6 +39,7 @@ import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.keyguard.KeyguardViewController; import com.android.systemui.Dumpable; +import com.android.systemui.biometrics.AuthController; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dump.DumpManager; @@ -165,6 +166,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp private BiometricModeListener mBiometricModeListener; private final MetricsLogger mMetricsLogger; + private final AuthController mAuthController; private static final class PendingAuthenticated { public final int userId; @@ -254,7 +256,8 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp PowerManager powerManager, NotificationMediaManager notificationMediaManager, WakefulnessLifecycle wakefulnessLifecycle, - ScreenLifecycle screenLifecycle) { + ScreenLifecycle screenLifecycle, + AuthController authController) { mContext = context; mPowerManager = powerManager; mShadeController = shadeController; @@ -275,6 +278,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp mKeyguardBypassController = keyguardBypassController; mKeyguardBypassController.setUnlockController(this); mMetricsLogger = metricsLogger; + mAuthController = authController; dumpManager.registerDumpable(getClass().getName(), this); } @@ -588,14 +592,16 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp return MODE_UNLOCK_COLLAPSING; } if (mKeyguardViewController.isShowing()) { - if (mKeyguardViewController.bouncerIsOrWillBeShowing() && unlockingAllowed) { + if ((mKeyguardViewController.bouncerIsOrWillBeShowing() + || mKeyguardBypassController.getAltBouncerShowing()) && unlockingAllowed) { if (bypass && mKeyguardBypassController.canPlaySubtleWindowAnimations()) { return MODE_UNLOCK_FADING; } else { return MODE_DISMISS_BOUNCER; } } else if (unlockingAllowed) { - return bypass ? MODE_UNLOCK_FADING : MODE_NONE; + return bypass || mAuthController.isUdfpsFingerDown() + ? MODE_UNLOCK_FADING : MODE_NONE; } else { return bypass ? MODE_SHOW_BOUNCER : MODE_NONE; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt index 26c6fe980ee1..99df3f18729e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt @@ -28,6 +28,7 @@ import com.android.systemui.dump.DumpManager import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.statusbar.NotificationLockscreenUserManager import com.android.systemui.statusbar.StatusBarState +import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.tuner.TunerService import java.io.FileDescriptor @@ -35,13 +36,18 @@ import java.io.PrintWriter import javax.inject.Inject @SysUISingleton -open class KeyguardBypassController : Dumpable { +open class KeyguardBypassController : Dumpable, StackScrollAlgorithm.BypassController { private val mKeyguardStateController: KeyguardStateController private val statusBarStateController: StatusBarStateController @BypassOverride private val bypassOverride: Int private var hasFaceFeature: Boolean private var pendingUnlock: PendingUnlock? = null + private val listeners = mutableListOf<OnBypassStateChangedListener>() + + private val faceAuthEnabledChangedCallback = object : KeyguardStateController.Callback { + override fun onFaceAuthEnabledChanged() = notifyListeners() + } @IntDef( FACE_UNLOCK_BYPASS_NO_OVERRIDE, @@ -67,6 +73,9 @@ open class KeyguardBypassController : Dumpable { lateinit var unlockController: BiometricUnlockController var isPulseExpanding = false + /** delegates to [bypassEnabled] but conforms to [StackScrollAlgorithm.BypassController] */ + override fun isBypassEnabled() = bypassEnabled + /** * If face unlock dismisses the lock screen or keeps user on keyguard for the current user. */ @@ -79,9 +88,13 @@ open class KeyguardBypassController : Dumpable { } return enabled && mKeyguardStateController.isFaceAuthEnabled } - private set + private set(value) { + field = value + notifyListeners() + } var bouncerShowing: Boolean = false + var altBouncerShowing: Boolean = false var launchingAffordance: Boolean = false var qSExpanded = false set(value) { @@ -135,6 +148,8 @@ open class KeyguardBypassController : Dumpable { }) } + private fun notifyListeners() = listeners.forEach { it.onBypassStateChanged(bypassEnabled) } + /** * Notify that the biometric unlock has happened. * @@ -172,6 +187,7 @@ open class KeyguardBypassController : Dumpable { if (bypassEnabled) { return when { bouncerShowing -> true + altBouncerShowing -> true statusBarStateController.state != StatusBarState.KEYGUARD -> false launchingAffordance -> false isPulseExpanding || qSExpanded -> false @@ -210,12 +226,39 @@ open class KeyguardBypassController : Dumpable { pw.println(" bypassEnabled: $bypassEnabled") pw.println(" canBypass: ${canBypass()}") pw.println(" bouncerShowing: $bouncerShowing") + pw.println(" altBouncerShowing: $altBouncerShowing") pw.println(" isPulseExpanding: $isPulseExpanding") pw.println(" launchingAffordance: $launchingAffordance") pw.println(" qSExpanded: $qSExpanded") pw.println(" hasFaceFeature: $hasFaceFeature") } + /** Registers a listener for bypass state changes. */ + fun registerOnBypassStateChangedListener(listener: OnBypassStateChangedListener) { + val start = listeners.isEmpty() + listeners.add(listener) + if (start) { + mKeyguardStateController.addCallback(faceAuthEnabledChangedCallback) + } + } + + /** + * Unregisters a listener for bypass state changes, previous registered with + * [registerOnBypassStateChangedListener] + */ + fun unregisterOnBypassStateChangedListener(listener: OnBypassStateChangedListener) { + listeners.remove(listener) + if (listeners.isEmpty()) { + mKeyguardStateController.removeCallback(faceAuthEnabledChangedCallback) + } + } + + /** Listener for bypass state change events. */ + interface OnBypassStateChangedListener { + /** Invoked when bypass becomes enabled or disabled. */ + fun onBypassStateChanged(isEnabled: Boolean) + } + companion object { const val BYPASS_FADE_DURATION = 67 diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightsOutNotifController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightsOutNotifController.java index 7d134057ee76..c213707a8953 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightsOutNotifController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightsOutNotifController.java @@ -21,6 +21,7 @@ import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.annotation.Nullable; +import android.view.InsetsState; import android.view.View; import android.view.WindowInsetsController.Appearance; import android.view.WindowInsetsController.Behavior; @@ -149,7 +150,7 @@ public class LightsOutNotifController { @Override public void onSystemBarAttributesChanged(int displayId, @Appearance int appearance, AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme, - @Behavior int behavior, boolean isFullscreen) { + @Behavior int behavior, InsetsState requestedState, String packageName) { if (displayId != mDisplayId) { return; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java index a2ea3da27b51..dcf5c6a5befe 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java @@ -1401,7 +1401,8 @@ public class NotificationPanelViewController extends PanelViewController { float lockIconPadding = 0; if (mLockIconViewController.getTop() != 0) { - lockIconPadding = mStatusBar.getDisplayHeight() - mLockIconViewController.getTop(); + lockIconPadding = mStatusBar.getDisplayHeight() - mLockIconViewController.getTop() + + mResources.getDimensionPixelSize(R.dimen.min_lock_icon_padding); } float bottomPadding = Math.max(mIndicationBottomPadding, mAmbientIndicationBottomPadding); @@ -1676,7 +1677,6 @@ public class NotificationPanelViewController extends PanelViewController { mView.getParent().requestDisallowInterceptTouchEvent(true); } if (mQsExpansionAnimator != null) { - onQsExpansionStarted(); mInitialHeightOnTouch = mQsExpansionHeight; mQsTracking = true; traceQsJank(true /* startTracing */, false /* wasCancelled */); @@ -3679,6 +3679,8 @@ public class NotificationPanelViewController extends PanelViewController { public void setAmbientIndicationBottomPadding(int ambientIndicationBottomPadding) { if (mAmbientIndicationBottomPadding != ambientIndicationBottomPadding) { mAmbientIndicationBottomPadding = ambientIndicationBottomPadding; + mLockIconViewController.setAmbientIndicationBottomPadding( + mAmbientIndicationBottomPadding); updateMaxDisplayedNotifications(true); } } 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 7f4dabd3f59f..b5d9bd67bd2d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java @@ -26,6 +26,7 @@ import android.media.session.MediaSessionLegacyHelper; import android.os.SystemClock; import android.os.UserHandle; import android.provider.Settings; +import android.util.Log; import android.view.GestureDetector; import android.view.InputDevice; import android.view.KeyEvent; @@ -66,6 +67,7 @@ import javax.inject.Inject; * Controller for {@link NotificationShadeWindowView}. */ public class NotificationShadeWindowViewController { + private static final String TAG = "NotifShadeWindowVC"; private final InjectionInflationController mInjectionInflationController; private final NotificationWakeUpCoordinator mCoordinator; private final PulseExpansionHandler mPulseExpansionHandler; @@ -213,6 +215,10 @@ public class NotificationShadeWindowViewController { mView.setInteractionEventHandler(new NotificationShadeWindowView.InteractionEventHandler() { @Override public Boolean handleDispatchTouchEvent(MotionEvent ev) { + if (mStatusBarView == null) { + Log.w(TAG, "Ignoring touch while statusBarView not yet set."); + return false; + } boolean isDown = ev.getActionMasked() == MotionEvent.ACTION_DOWN; boolean isUp = ev.getActionMasked() == MotionEvent.ACTION_UP; boolean isCancel = ev.getActionMasked() == MotionEvent.ACTION_CANCEL; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java index ed7ab6cf9f37..7b110a0ec01f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java @@ -107,7 +107,8 @@ public class PhoneStatusBarPolicy private final String mSlotBluetooth; private final String mSlotTty; private final String mSlotZen; - private final String mSlotVolume; + private final String mSlotMute; + private final String mSlotVibrate; private final String mSlotAlarmClock; private final String mSlotManagedProfile; private final String mSlotRotate; @@ -149,7 +150,8 @@ public class PhoneStatusBarPolicy private final PrivacyLogger mPrivacyLogger; private boolean mZenVisible; - private boolean mVolumeVisible; + private boolean mVibrateVisible; + private boolean mMuteVisible; private boolean mCurrentUserSetup; private boolean mManagedProfileIconVisible = false; @@ -207,7 +209,8 @@ public class PhoneStatusBarPolicy mSlotBluetooth = resources.getString(com.android.internal.R.string.status_bar_bluetooth); mSlotTty = resources.getString(com.android.internal.R.string.status_bar_tty); mSlotZen = resources.getString(com.android.internal.R.string.status_bar_zen); - mSlotVolume = resources.getString(com.android.internal.R.string.status_bar_volume); + mSlotMute = resources.getString(com.android.internal.R.string.status_bar_mute); + mSlotVibrate = resources.getString(com.android.internal.R.string.status_bar_volume); mSlotAlarmClock = resources.getString(com.android.internal.R.string.status_bar_alarm_clock); mSlotManagedProfile = resources.getString( com.android.internal.R.string.status_bar_managed_profile); @@ -264,9 +267,14 @@ public class PhoneStatusBarPolicy mIconController.setIcon(mSlotZen, R.drawable.stat_sys_dnd, null); mIconController.setIconVisibility(mSlotZen, false); - // volume - mIconController.setIcon(mSlotVolume, R.drawable.stat_sys_ringer_vibrate, null); - mIconController.setIconVisibility(mSlotVolume, false); + // vibrate + mIconController.setIcon(mSlotVibrate, R.drawable.stat_sys_ringer_vibrate, + mResources.getString(R.string.accessibility_ringer_vibrate)); + mIconController.setIconVisibility(mSlotVibrate, false); + // mute + mIconController.setIcon(mSlotMute, R.drawable.stat_sys_ringer_silent, + mResources.getString(R.string.accessibility_ringer_silent)); + mIconController.setIconVisibility(mSlotMute, false); updateVolumeZen(); // cast @@ -372,9 +380,8 @@ public class PhoneStatusBarPolicy int zenIconId = 0; String zenDescription = null; - boolean volumeVisible = false; - int volumeIconId = 0; - String volumeDescription = null; + boolean vibrateVisible = false; + boolean muteVisible = false; int zen = mZenController.getZen(); if (DndTile.isVisible(mSharedPreferences) || DndTile.isCombinedIcon(mSharedPreferences)) { @@ -396,13 +403,9 @@ public class PhoneStatusBarPolicy mRingerModeTracker.getRingerModeInternal().getValue(); if (ringerModeInternal != null) { if (ringerModeInternal == AudioManager.RINGER_MODE_VIBRATE) { - volumeVisible = true; - volumeIconId = R.drawable.stat_sys_ringer_vibrate; - volumeDescription = mResources.getString(R.string.accessibility_ringer_vibrate); + vibrateVisible = true; } else if (ringerModeInternal == AudioManager.RINGER_MODE_SILENT) { - volumeVisible = true; - volumeIconId = R.drawable.stat_sys_ringer_silent; - volumeDescription = mResources.getString(R.string.accessibility_ringer_silent); + muteVisible = true; } } } @@ -415,13 +418,16 @@ public class PhoneStatusBarPolicy mZenVisible = zenVisible; } - if (volumeVisible) { - mIconController.setIcon(mSlotVolume, volumeIconId, volumeDescription); + if (vibrateVisible != mVibrateVisible) { + mIconController.setIconVisibility(mSlotVibrate, vibrateVisible); + mVibrateVisible = vibrateVisible; } - if (volumeVisible != mVolumeVisible) { - mIconController.setIconVisibility(mSlotVolume, volumeVisible); - mVolumeVisible = volumeVisible; + + if (muteVisible != mMuteVisible) { + mIconController.setIconVisibility(mSlotMute, muteVisible); + mMuteVisible = muteVisible; } + updateAlarm(); } 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 89711fa6b11e..e3b2a2f56df3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -104,6 +104,7 @@ import android.util.Slog; import android.view.Display; import android.view.IRemoteAnimationRunner; import android.view.IWindowManager; +import android.view.InsetsState; import android.view.InsetsState.InternalInsetsType; import android.view.KeyEvent; import android.view.MotionEvent; @@ -247,6 +248,7 @@ import com.android.systemui.volume.VolumeComponent; import com.android.systemui.wmshell.BubblesManager; import com.android.wm.shell.bubbles.Bubbles; import com.android.wm.shell.legacysplitscreen.LegacySplitScreen; +import com.android.wm.shell.startingsurface.StartingSurface; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -685,9 +687,7 @@ public class StatusBar extends SystemUI implements DemoMode, new FalsingManager.FalsingBeliefListener() { @Override public void onFalse() { - // Hides quick settings. - mNotificationPanelViewController.resetViews(true); - // Hides bouncer and quick-quick settings. + // Hides quick settings, bouncer, and quick-quick settings. mStatusBarKeyguardViewManager.reset(true); } }; @@ -705,6 +705,7 @@ public class StatusBar extends SystemUI implements DemoMode, private final Optional<BubblesManager> mBubblesManagerOptional; private final Optional<Bubbles> mBubblesOptional; private final Bubbles.BubbleExpandListener mBubbleExpandListener; + private final Optional<StartingSurface> mStartingSurfaceOptional; private ActivityIntentHelper mActivityIntentHelper; private NotificationStackScrollLayoutController mStackScrollerController; @@ -804,7 +805,8 @@ public class StatusBar extends SystemUI implements DemoMode, LockscreenShadeTransitionController lockscreenShadeTransitionController, FeatureFlags featureFlags, KeyguardUnlockAnimationController keyguardUnlockAnimationController, - UnlockedScreenOffAnimationController unlockedScreenOffAnimationController) { + UnlockedScreenOffAnimationController unlockedScreenOffAnimationController, + Optional<StartingSurface> startingSurfaceOptional) { super(context); mNotificationsController = notificationsController; mLightBarController = lightBarController; @@ -891,6 +893,7 @@ public class StatusBar extends SystemUI implements DemoMode, mUnlockedScreenOffAnimationController = unlockedScreenOffAnimationController; mLockscreenShadeTransitionController = lockscreenShadeTransitionController; + mStartingSurfaceOptional = startingSurfaceOptional; lockscreenShadeTransitionController.setStatusbar(this); mExpansionChangedListeners = new ArrayList<>(); @@ -984,7 +987,8 @@ public class StatusBar extends SystemUI implements DemoMode, showTransientUnchecked(); } onSystemBarAttributesChanged(mDisplayId, result.mAppearance, result.mAppearanceRegions, - result.mNavbarColorManagedByIme, result.mBehavior, result.mAppFullscreen); + result.mNavbarColorManagedByIme, result.mBehavior, result.mRequestedState, + result.mPackageName); // StatusBarManagerService has a back up of IME token and it's restored here. setImeWindowStatus(mDisplayId, result.mImeToken, result.mImeWindowVis, @@ -1419,7 +1423,9 @@ public class StatusBar extends SystemUI implements DemoMode, private void setUpPresenter() { // Set up the initial notification state. - mActivityLaunchAnimator = new ActivityLaunchAnimator(this, mContext); + mActivityLaunchAnimator = new ActivityLaunchAnimator(this, + mStartingSurfaceOptional.orElse(null), + mContext); mNotificationAnimationProvider = new NotificationLaunchAnimatorControllerProvider( mNotificationShadeWindowViewController, mStackScrollerController.getNotificationListContainer(), @@ -1447,7 +1453,7 @@ public class StatusBar extends SystemUI implements DemoMode, .setNotificationPresenter(mPresenter) .setNotificationPanelViewController(mNotificationPanelViewController) .build(); - mStackScroller.setNotificationActivityStarter(mNotificationActivityStarter); + mStackScrollerController.setNotificationActivityStarter(mNotificationActivityStarter); mGutsManager.setNotificationActivityStarter(mNotificationActivityStarter); mNotificationsController.initialize( @@ -2477,7 +2483,7 @@ public class StatusBar extends SystemUI implements DemoMode, @Override public void onSystemBarAttributesChanged(int displayId, @Appearance int appearance, AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme, - @Behavior int behavior, boolean isFullscreen) { + @Behavior int behavior, InsetsState requestedState, String packageName) { if (displayId != mDisplayId) { return; } @@ -2490,7 +2496,8 @@ public class StatusBar extends SystemUI implements DemoMode, mStatusBarMode, navbarColorManagedByIme); updateBubblesVisibility(); - mStatusBarStateController.setFullscreenState(isFullscreen); + mStatusBarStateController.setSystemBarAttributes( + appearance, behavior, requestedState, packageName); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index 5a3acdb71752..95fd886d6046 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -42,6 +42,8 @@ import androidx.annotation.VisibleForTesting; import com.android.internal.util.LatencyTracker; import com.android.internal.widget.LockPatternUtils; +import com.android.keyguard.KeyguardMessageArea; +import com.android.keyguard.KeyguardMessageAreaController; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.keyguard.KeyguardViewController; @@ -50,6 +52,7 @@ import com.android.systemui.DejankUtils; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dock.DockManager; import com.android.systemui.keyguard.FaceAuthScreenBrightnessController; +import com.android.systemui.keyguard.WakefulnessLifecycle; import com.android.systemui.navigationbar.NavigationModeController; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.shared.system.QuickStepContract; @@ -80,7 +83,7 @@ import javax.inject.Inject; public class StatusBarKeyguardViewManager implements RemoteInputController.Callback, StatusBarStateController.StateListener, ConfigurationController.ConfigurationListener, PanelExpansionListener, NavigationModeController.ModeChangedListener, - KeyguardViewController { + KeyguardViewController, WakefulnessLifecycle.Observer { // When hiding the Keyguard with timing supplied from WindowManager, better be early than late. private static final long HIDE_TIMING_CORRECTION_MS = - 16 * 3; @@ -104,6 +107,10 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb private final NotificationShadeWindowController mNotificationShadeWindowController; private final Optional<FaceAuthScreenBrightnessController> mFaceAuthScreenBrightnessController; private final KeyguardBouncer.Factory mKeyguardBouncerFactory; + private final WakefulnessLifecycle mWakefulnessLifecycle; + private final UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController; + private final KeyguardMessageAreaController.Factory mKeyguardMessageAreaFactory; + private KeyguardMessageAreaController mKeyguardMessageAreaController; private final BouncerExpansionCallback mExpansionCallback = new BouncerExpansionCallback() { @Override public void onFullyShown() { @@ -189,6 +196,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb private boolean mLastPulsing; private int mLastBiometricMode; private boolean mQsExpanded; + private boolean mAnimatedToSleep; private OnDismissAction mAfterKeyguardGoneAction; private Runnable mKeyguardGoneCancelAction; @@ -232,7 +240,10 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb KeyguardStateController keyguardStateController, Optional<FaceAuthScreenBrightnessController> faceAuthScreenBrightnessController, NotificationMediaManager notificationMediaManager, - KeyguardBouncer.Factory keyguardBouncerFactory) { + KeyguardBouncer.Factory keyguardBouncerFactory, + WakefulnessLifecycle wakefulnessLifecycle, + UnlockedScreenOffAnimationController unlockedScreenOffAnimationController, + KeyguardMessageAreaController.Factory keyguardMessageAreaFactory) { mContext = context; mViewMediatorCallback = callback; mLockPatternUtils = lockPatternUtils; @@ -246,6 +257,9 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb mDockManager = dockManager; mFaceAuthScreenBrightnessController = faceAuthScreenBrightnessController; mKeyguardBouncerFactory = keyguardBouncerFactory; + mWakefulnessLifecycle = wakefulnessLifecycle; + mUnlockedScreenOffAnimationController = unlockedScreenOffAnimationController; + mKeyguardMessageAreaFactory = keyguardMessageAreaFactory; } @Override @@ -263,6 +277,8 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb notificationPanelViewController.addExpansionListener(this); mBypassController = bypassController; mNotificationContainer = notificationContainer; + mKeyguardMessageAreaController = mKeyguardMessageAreaFactory.create( + KeyguardMessageArea.findSecurityMessageDisplay(container)); mFaceAuthScreenBrightnessController.ifPresent((it) -> { View overlay = new View(mContext); container.addView(overlay); @@ -301,6 +317,20 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb mDockManager.addListener(mDockEventListener); mIsDocked = mDockManager.isDocked(); } + mWakefulnessLifecycle.addObserver(new WakefulnessLifecycle.Observer() { + @Override + public void onFinishedWakingUp() { + mAnimatedToSleep = false; + updateStates(); + } + + @Override + public void onFinishedGoingToSleep() { + mAnimatedToSleep = + mUnlockedScreenOffAnimationController.isScreenOffAnimationPlaying(); + updateStates(); + } + }); } @Override @@ -390,9 +420,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb */ public void showGenericBouncer(boolean scrimmed) { if (mAlternateAuthInterceptor != null) { - if (mAlternateAuthInterceptor.showAlternateAuthBouncer()) { - mStatusBar.updateScrimController(); - } + updateAlternateAuthShowing(mAlternateAuthInterceptor.showAlternateAuthBouncer()); return; } @@ -459,9 +487,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb mKeyguardGoneCancelAction = null; } - if (mAlternateAuthInterceptor.showAlternateAuthBouncer()) { - mStatusBar.updateScrimController(); - } + updateAlternateAuthShowing(mAlternateAuthInterceptor.showAlternateAuthBouncer()); return; } @@ -495,6 +521,9 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb @Override public void reset(boolean hideBouncerWhenShowing) { if (mShowing) { + // Hide quick settings. + mNotificationPanelViewController.resetViews(/* animate= */ true); + // Hide bouncer and quick-quick settings. if (mOccluded && !mDozing) { mStatusBar.hideKeyguard(); if (hideBouncerWhenShowing || mBouncer.needsFullscreenBouncer()) { @@ -513,9 +542,19 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb * Stop showing any alternate auth methods */ public void resetAlternateAuth(boolean forceUpdateScrim) { - if ((mAlternateAuthInterceptor != null + final boolean updateScrim = (mAlternateAuthInterceptor != null && mAlternateAuthInterceptor.hideAlternateAuthBouncer()) - || forceUpdateScrim) { + || forceUpdateScrim; + updateAlternateAuthShowing(updateScrim); + } + + private void updateAlternateAuthShowing(boolean updateScrim) { + if (mKeyguardMessageAreaController != null) { + mKeyguardMessageAreaController.setAltBouncerShowing(isShowingAlternateAuth()); + } + mBypassController.setAltBouncerShowing(isShowingAlternateAuth()); + + if (updateScrim) { mStatusBar.updateScrimController(); } } @@ -852,7 +891,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb @Override public boolean isBouncerShowing() { - return mBouncer.isShowing(); + return mBouncer.isShowing() || isShowingAlternateAuth(); } @Override @@ -984,7 +1023,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb boolean hideWhileDozing = mDozing && biometricMode != MODE_WAKE_AND_UNLOCK_PULSING; boolean keyguardWithGestureNav = (keyguardShowing && !mDozing || mPulsing && !mIsDocked) && mGesturalNav; - return (!keyguardShowing && !hideWhileDozing || mBouncer.isShowing() + return (!mAnimatedToSleep && !keyguardShowing && !hideWhileDozing || mBouncer.isShowing() || mRemoteInputActive || keyguardWithGestureNav || mGlobalActionsVisible); } @@ -1069,7 +1108,14 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb } public void showBouncerMessage(String message, ColorStateList colorState) { - mBouncer.showMessage(message, colorState); + if (isShowingAlternateAuth()) { + if (mKeyguardMessageAreaController != null) { + mKeyguardMessageAreaController.setNextMessageColor(colorState); + mKeyguardMessageAreaController.setMessage(message); + } + } else { + mBouncer.showMessage(message, colorState); + } } @Override 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 98b9cc9bc716..9a6dd38ffca5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java @@ -514,7 +514,8 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit InteractionJankMonitor.CUJ_SHADE_APP_LAUNCH_FROM_HISTORY_BUTTON ); ActivityLaunchAnimator.Controller animationController = - new StatusBarLaunchAnimatorController(viewController, mStatusBar, + viewController == null ? null + : new StatusBarLaunchAnimatorController(viewController, mStatusBar, true /* isActivityIntent */); mActivityLaunchAnimator.startIntentWithAnimation(animationController, animate, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java index 2611ab5f7016..716d1dbc6462 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java @@ -109,6 +109,7 @@ import com.android.systemui.volume.VolumeComponent; import com.android.systemui.wmshell.BubblesManager; import com.android.wm.shell.bubbles.Bubbles; import com.android.wm.shell.legacysplitscreen.LegacySplitScreen; +import com.android.wm.shell.startingsurface.StartingSurface; import java.util.Optional; import java.util.concurrent.Executor; @@ -218,7 +219,8 @@ public interface StatusBarPhoneModule { LockscreenShadeTransitionController transitionController, FeatureFlags featureFlags, KeyguardUnlockAnimationController keyguardUnlockAnimationController, - UnlockedScreenOffAnimationController unlockedScreenOffAnimationController) { + UnlockedScreenOffAnimationController unlockedScreenOffAnimationController, + Optional<StartingSurface> startingSurfaceOptional) { return new StatusBar( context, notificationsController, @@ -306,6 +308,7 @@ public interface StatusBarPhoneModule { transitionController, featureFlags, keyguardUnlockAnimationController, - unlockedScreenOffAnimationController); + unlockedScreenOffAnimationController, + startingSurfaceOptional); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyController.java index d7d1e737661e..e01b95e81da8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyController.java @@ -17,6 +17,7 @@ package com.android.systemui.statusbar.policy; import android.hardware.SensorPrivacyManager.Sensors.Sensor; +import android.hardware.SensorPrivacyManager.Sources.Source; public interface IndividualSensorPrivacyController extends CallbackController<IndividualSensorPrivacyController.Callback> { @@ -26,9 +27,9 @@ public interface IndividualSensorPrivacyController extends boolean isSensorBlocked(@Sensor int sensor); - void setSensorBlocked(@Sensor int sensor, boolean blocked); + void setSensorBlocked(@Source int source, @Sensor int sensor, boolean blocked); - void suppressSensorPrivacyReminders(String packageName, boolean suppress); + void suppressSensorPrivacyReminders(int sensor, boolean suppress); interface Callback { void onSensorBlockedChanged(@Sensor int sensor, boolean blocked); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyControllerImpl.java index f58a7c030b80..1d71301c7454 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyControllerImpl.java @@ -21,6 +21,7 @@ import static android.hardware.SensorPrivacyManager.Sensors.MICROPHONE; import android.hardware.SensorPrivacyManager; import android.hardware.SensorPrivacyManager.Sensors.Sensor; +import android.hardware.SensorPrivacyManager.Sources.Source; import android.util.ArraySet; import android.util.SparseBooleanArray; @@ -62,13 +63,13 @@ public class IndividualSensorPrivacyControllerImpl implements IndividualSensorPr } @Override - public void setSensorBlocked(@Sensor int sensor, boolean blocked) { - mSensorPrivacyManager.setSensorPrivacyForProfileGroup(sensor, blocked); + public void setSensorBlocked(@Source int source, @Sensor int sensor, boolean blocked) { + mSensorPrivacyManager.setSensorPrivacyForProfileGroup(source, sensor, blocked); } @Override - public void suppressSensorPrivacyReminders(String packageName, boolean suppress) { - mSensorPrivacyManager.suppressSensorPrivacyReminders(packageName, suppress); + public void suppressSensorPrivacyReminders(int sensor, boolean suppress) { + mSensorPrivacyManager.suppressSensorPrivacyReminders(sensor, suppress); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java index 1f1817cd29f0..5e70d0dbc418 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java @@ -21,7 +21,7 @@ import android.content.res.Resources; import android.database.DataSetObserver; import android.graphics.drawable.Drawable; import android.graphics.drawable.LayerDrawable; -import android.os.UserManager; +import android.os.UserHandle; import android.text.TextUtils; import android.util.Log; import android.view.View; @@ -76,7 +76,6 @@ public class KeyguardQsUserSwitchController extends ViewController<UserAvatarVie private final KeyguardVisibilityHelper mKeyguardVisibilityHelper; private final KeyguardUserDetailAdapter mUserDetailAdapter; private NotificationPanelViewController mNotificationPanelViewController; - private UserManager mUserManager; UserSwitcherController.UserRecord mCurrentUser; // State info for the user switch and keyguard @@ -115,7 +114,6 @@ public class KeyguardQsUserSwitchController extends ViewController<UserAvatarVie UserAvatarView view, Context context, @Main Resources resources, - UserManager userManager, ScreenLifecycle screenLifecycle, UserSwitcherController userSwitcherController, KeyguardStateController keyguardStateController, @@ -129,7 +127,6 @@ public class KeyguardQsUserSwitchController extends ViewController<UserAvatarVie if (DEBUG) Log.d(TAG, "New KeyguardQsUserSwitchController"); mContext = context; mResources = resources; - mUserManager = userManager; mScreenLifecycle = screenLifecycle; mUserSwitcherController = userSwitcherController; mKeyguardStateController = keyguardStateController; @@ -227,47 +224,39 @@ public class KeyguardQsUserSwitchController extends ViewController<UserAvatarVie return; } - if (mCurrentUser == null) { - mView.setVisibility(View.GONE); - return; - } - - mView.setVisibility(View.VISIBLE); - - String currentUserName = mCurrentUser.info.name; String contentDescription = null; - - if (!TextUtils.isEmpty(currentUserName)) { + if (mCurrentUser != null && mCurrentUser.info != null && !TextUtils.isEmpty( + mCurrentUser.info.name)) { + // If we know the current user's name, have TalkBack to announce "Signed in as [user + // name]" when the icon is selected + contentDescription = mContext.getString(R.string.accessibility_quick_settings_user, + mCurrentUser.info.name); + } else { + // As a fallback, have TalkBack announce "Switch user" contentDescription = mContext.getString( - R.string.accessibility_quick_settings_user, - currentUserName); + R.string.accessibility_multi_user_switch_switcher); } if (!TextUtils.equals(mView.getContentDescription(), contentDescription)) { mView.setContentDescription(contentDescription); } - mView.setDrawableWithBadge(getCurrentUserIcon().mutate(), mCurrentUser.resolveId()); + int userId = mCurrentUser != null ? mCurrentUser.resolveId() : UserHandle.USER_NULL; + mView.setDrawableWithBadge(getCurrentUserIcon().mutate(), userId); } Drawable getCurrentUserIcon() { Drawable drawable; - if (mCurrentUser.picture == null) { - if (mCurrentUser.isCurrent && mCurrentUser.isGuest) { + if (mCurrentUser == null || mCurrentUser.picture == null) { + if (mCurrentUser != null && mCurrentUser.isGuest) { drawable = mContext.getDrawable(R.drawable.ic_avatar_guest_user); } else { - drawable = mAdapter.getIconDrawable(mContext, mCurrentUser); - } - int iconColorRes; - if (mCurrentUser.isSwitchToEnabled) { - iconColorRes = R.color.kg_user_switcher_avatar_icon_color; - } else { - iconColorRes = R.color.kg_user_switcher_restricted_avatar_icon_color; + drawable = mContext.getDrawable(R.drawable.ic_avatar_user); } + int iconColorRes = R.color.kg_user_switcher_avatar_icon_color; drawable.setTint(mResources.getColor(iconColorRes, mContext.getTheme())); } else { - int avatarSize = - (int) mResources.getDimension(R.dimen.kg_framed_avatar_size); + int avatarSize = (int) mResources.getDimension(R.dimen.kg_framed_avatar_size); drawable = new CircleFramedDrawable(mCurrentUser.picture, avatarSize); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java index fcfc9670b8b0..742b1ab69727 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java @@ -245,5 +245,11 @@ public interface KeyguardStateController extends CallbackController<Callback> { * animation. */ default void onKeyguardDismissAmountChanged() {} + + /** + * Triggered when face auth becomes available or unavailable. Value should be queried with + * {@link KeyguardStateController#isFaceAuthEnabled()}. + */ + default void onFaceAuthEnabledChanged() {} } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java index d9a5269439e6..fa6111589bff 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java @@ -695,7 +695,7 @@ public class NetworkControllerImpl extends BroadcastReceiver cb.setIsAirplaneMode(new IconState(mAirplaneMode, TelephonyIcons.FLIGHT_MODE_ICON, R.string.accessibility_airplane_mode, mContext)); cb.setNoSims(mHasNoSubs, mSimDetected); - if (mProviderModelBehavior) { + if (mProviderModelSetting) { cb.setConnectivityStatus(mNoDefaultNetwork, !mInetCondition, mNoNetworksAvailable); } mWifiSignalController.notifyListeners(cb); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java index e2b6895e7039..4e921a036b36 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java @@ -67,6 +67,7 @@ import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dagger.qualifiers.UiBackground; import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.DetailAdapter; import com.android.systemui.qs.QSUserSwitcherEvent; import com.android.systemui.qs.tiles.UserDetailView; @@ -131,6 +132,7 @@ public class UserSwitcherController implements Dumpable { private final Executor mUiBgExecutor; private final boolean mGuestUserAutoCreated; private final AtomicBoolean mGuestCreationScheduled; + private FalsingManager mFalsingManager; @Inject public UserSwitcherController(Context context, @@ -139,6 +141,7 @@ public class UserSwitcherController implements Dumpable { ActivityStarter activityStarter, BroadcastDispatcher broadcastDispatcher, UiEventLogger uiEventLogger, + FalsingManager falsingManager, TelephonyListenerManager telephonyListenerManager, IActivityTaskManager activityTaskManager, UserDetailAdapter userDetailAdapter, @@ -148,6 +151,7 @@ public class UserSwitcherController implements Dumpable { mTelephonyListenerManager = telephonyListenerManager; mActivityTaskManager = activityTaskManager; mUiEventLogger = uiEventLogger; + mFalsingManager = falsingManager; mGuestResumeSessionReceiver = new GuestResumeSessionReceiver(this, mUiEventLogger); mUserDetailAdapter = userDetailAdapter; mUiBgExecutor = uiBgExecutor; @@ -1031,6 +1035,11 @@ public class UserSwitcherController implements Dumpable { @Override public void onClick(DialogInterface dialog, int which) { + int penalty = which == BUTTON_NEGATIVE ? FalsingManager.NO_PENALTY + : FalsingManager.HIGH_PENALTY; + if (mFalsingManager.isFalseTap(penalty)) { + return; + } if (which == BUTTON_NEGATIVE) { cancel(); } else { @@ -1057,6 +1066,11 @@ public class UserSwitcherController implements Dumpable { @Override public void onClick(DialogInterface dialog, int which) { + int penalty = which == BUTTON_NEGATIVE ? FalsingManager.NO_PENALTY + : FalsingManager.MODERATE_PENALTY; + if (mFalsingManager.isFalseTap(penalty)) { + return; + } if (which == BUTTON_NEGATIVE) { cancel(); } else { diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java index 11ddbd045cd4..81999b534046 100644 --- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java +++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java @@ -450,19 +450,23 @@ public class ThemeOverlayController extends SystemUI implements Dumpable { OverlayIdentifier systemPalette = categoryToPackage.get(OVERLAY_CATEGORY_SYSTEM_PALETTE); if (mIsMonetEnabled && systemPalette != null && systemPalette.getPackageName() != null) { try { - int color = Integer.parseInt(systemPalette.getPackageName().toLowerCase(), 16); + String colorString = systemPalette.getPackageName().toLowerCase(); + if (!colorString.startsWith("#")) { + colorString = "#" + colorString; + } + int color = Color.parseColor(colorString); mNeutralOverlay = getOverlay(color, NEUTRAL); mNeedsOverlayCreation = true; categoryToPackage.remove(OVERLAY_CATEGORY_SYSTEM_PALETTE); - } catch (NumberFormatException e) { - Log.w(TAG, "Invalid color definition: " + systemPalette.getPackageName()); + } catch (Exception e) { + // Color.parseColor doesn't catch any exceptions from the calls it makes + Log.w(TAG, "Invalid color definition: " + systemPalette.getPackageName(), e); } } else if (!mIsMonetEnabled && systemPalette != null) { try { // It's possible that we flipped the flag off and still have a @ColorInt in the // setting. We need to sanitize the input, otherwise the overlay transaction will // fail. - Integer.parseInt(systemPalette.getPackageName().toLowerCase(), 16); categoryToPackage.remove(OVERLAY_CATEGORY_SYSTEM_PALETTE); } catch (NumberFormatException e) { // This is a package name. All good, let's continue @@ -473,12 +477,17 @@ public class ThemeOverlayController extends SystemUI implements Dumpable { OverlayIdentifier accentPalette = categoryToPackage.get(OVERLAY_CATEGORY_ACCENT_COLOR); if (mIsMonetEnabled && accentPalette != null && accentPalette.getPackageName() != null) { try { - int color = Integer.parseInt(accentPalette.getPackageName().toLowerCase(), 16); + String colorString = accentPalette.getPackageName().toLowerCase(); + if (!colorString.startsWith("#")) { + colorString = "#" + colorString; + } + int color = Color.parseColor(colorString); mSecondaryOverlay = getOverlay(color, ACCENT); mNeedsOverlayCreation = true; categoryToPackage.remove(OVERLAY_CATEGORY_ACCENT_COLOR); - } catch (NumberFormatException e) { - Log.w(TAG, "Invalid color definition: " + accentPalette.getPackageName()); + } catch (Exception e) { + // Color.parseColor doesn't catch any exceptions from the calls it makes + Log.w(TAG, "Invalid color definition: " + accentPalette.getPackageName(), e); } } else if (!mIsMonetEnabled && accentPalette != null) { try { diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java index 94467329b6c9..f31762819d00 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java @@ -1750,7 +1750,7 @@ public class VolumeDialogImpl implements VolumeDialog, mContext, android.R.attr.colorBackgroundFloating); final ColorStateList inverseTextTint = Utils.getColorAttr( - mContext, com.android.internal.R.attr.textColorPrimaryInverse); + mContext, com.android.internal.R.attr.textColorOnAccent); row.sliderProgressSolid.setTintList(colorTint); if (row.sliderBgIcon != null) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java index 5617f1b6316b..1561b2028748 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java @@ -507,6 +507,30 @@ public class MagnificationModeSwitchTest extends SysuiTestCase { expectedY, mWindowManager.getLayoutParamsFromAttachedView().y); } + @Test + public void onScreenSizeChanged_buttonIsShowingOnTheRightSide_expectedPosition() { + final Rect windowBounds = mWindowManager.getCurrentWindowMetrics().getBounds(); + mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN); + final Rect oldDraggableBounds = new Rect(mMagnificationModeSwitch.mDraggableWindowBounds); + final float windowHeightFraction = + (float) (mWindowManager.getLayoutParamsFromAttachedView().y + - oldDraggableBounds.top) / oldDraggableBounds.height(); + + // The window bounds and the draggable bounds are changed due to the screen size change. + final Rect tmpRect = new Rect(windowBounds); + tmpRect.scale(2); + final Rect newWindowBounds = new Rect(tmpRect); + mWindowManager.setWindowBounds(newWindowBounds); + mMagnificationModeSwitch.onConfigurationChanged(ActivityInfo.CONFIG_SCREEN_SIZE); + + final int expectedX = mMagnificationModeSwitch.mDraggableWindowBounds.right; + final int expectedY = (int) (windowHeightFraction + * mMagnificationModeSwitch.mDraggableWindowBounds.height()) + + mMagnificationModeSwitch.mDraggableWindowBounds.top; + assertEquals(expectedX, mWindowManager.getLayoutParamsFromAttachedView().x); + assertEquals(expectedY, mWindowManager.getLayoutParamsFromAttachedView().y); + } + private void assertModeUnchanged(int expectedMode) { final int actualMode = Settings.Secure.getInt(mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE, 0); diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt index d01cdd45181f..33cc7821eba4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt @@ -14,12 +14,14 @@ import android.view.IRemoteAnimationFinishedCallback import android.view.RemoteAnimationAdapter import android.view.RemoteAnimationTarget import android.view.SurfaceControl +import android.view.View import android.view.ViewGroup import android.widget.LinearLayout import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.eq +import com.android.wm.shell.startingsurface.StartingSurface import junit.framework.Assert.assertFalse import junit.framework.Assert.assertNotNull import junit.framework.Assert.assertNull @@ -47,13 +49,14 @@ class ActivityLaunchAnimatorTest : SysuiTestCase() { @Mock lateinit var keyguardHandler: ActivityLaunchAnimator.KeyguardHandler @Spy private val controller = TestLaunchAnimatorController(launchContainer) @Mock lateinit var iCallback: IRemoteAnimationFinishedCallback + @Mock lateinit var startingSurface: StartingSurface private lateinit var activityLaunchAnimator: ActivityLaunchAnimator @get:Rule val rule = MockitoJUnit.rule() @Before fun setup() { - activityLaunchAnimator = ActivityLaunchAnimator(keyguardHandler, mContext) + activityLaunchAnimator = ActivityLaunchAnimator(keyguardHandler, startingSurface, mContext) } private fun startIntentWithAnimation( @@ -117,7 +120,7 @@ class ActivityLaunchAnimatorTest : SysuiTestCase() { @Test fun animatesIfActivityIsAlreadyOpenAndIsOnKeyguard() { `when`(keyguardHandler.isOnKeyguard()).thenReturn(true) - val animator = ActivityLaunchAnimator(keyguardHandler, context) + val animator = ActivityLaunchAnimator(keyguardHandler, startingSurface, context) val willAnimateCaptor = ArgumentCaptor.forClass(Boolean::class.java) var animationAdapter: RemoteAnimationAdapter? = null @@ -175,6 +178,11 @@ class ActivityLaunchAnimatorTest : SysuiTestCase() { verify(controller).onLaunchAnimationStart(anyBoolean()) } + @Test + fun controllerFromOrphanViewReturnsNull() { + assertNull(ActivityLaunchAnimator.Controller.fromView(View(mContext))) + } + private fun fakeWindow(): RemoteAnimationTarget { val bounds = Rect(10 /* left */, 20 /* top */, 30 /* right */, 40 /* bottom */) val taskInfo = ActivityManager.RunningTaskInfo() diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/GhostedViewLaunchAnimatorControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/GhostedViewLaunchAnimatorControllerTest.kt new file mode 100644 index 000000000000..8cba25dc1b92 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/animation/GhostedViewLaunchAnimatorControllerTest.kt @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.animation + +import android.testing.AndroidTestingRunner +import android.testing.TestableLooper +import android.widget.LinearLayout +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import org.junit.Test +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidTestingRunner::class) +@TestableLooper.RunWithLooper +class GhostedViewLaunchAnimatorControllerTest : SysuiTestCase() { + @Test + fun animatingOrphanViewDoesNotCrash() { + val ghostedView = LinearLayout(mContext) + val controller = GhostedViewLaunchAnimatorController(ghostedView) + val state = ActivityLaunchAnimator.State(top = 0, bottom = 0, left = 0, right = 0) + + controller.onIntentStarted(willAnimate = true) + controller.onLaunchAnimationStart(isExpandingFullyAbove = true) + controller.onLaunchAnimationProgress(state, progress = 0f, linearProgress = 0f) + controller.onLaunchAnimationEnd(isExpandingFullyAbove = true) + } +}
\ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintViewTest.java index fcdf702495d2..5cd781085b15 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintViewTest.java @@ -138,6 +138,31 @@ public class AuthBiometricFaceToFingerprintViewTest extends SysuiTestCase { } @Test + public void testStateUpdated_whenSwitchToFingerprint_invokesCallbacks() { + class TestModalityListener implements ModalityListener { + public int switchCount = 0; + + @Override + public void onModalitySwitched(int oldModality, int newModality) { + assertEquals(TYPE_FINGERPRINT, newModality); + assertEquals(TYPE_FACE, oldModality); + switchCount++; + } + } + final TestModalityListener modalityListener = new TestModalityListener(); + + mFaceToFpView.onDialogAnimatedIn(); + mFaceToFpView.setModalityListener(modalityListener); + + assertEquals(0, modalityListener.switchCount); + + mFaceToFpView.updateState(AuthBiometricFaceToFingerprintView.STATE_ERROR); + mFaceToFpView.updateState(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING); + + assertEquals(1, modalityListener.switchCount); + } + + @Test public void testModeUpdated_onSoftError_whenSwitchToFingerprint() { mFaceToFpView.onDialogAnimatedIn(); mFaceToFpView.onAuthenticationFailed(TYPE_FACE, "no face"); diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java index 9774ea98ff0d..e94f836337a9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java @@ -20,7 +20,9 @@ import static android.hardware.biometrics.BiometricManager.Authenticators; import static android.hardware.biometrics.BiometricManager.BIOMETRIC_MULTI_SENSOR_FACE_THEN_FINGERPRINT; import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertNull; +import static junit.framework.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; @@ -55,10 +57,12 @@ import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback; import android.os.Bundle; import android.os.RemoteException; -import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableContext; import android.testing.TestableLooper.RunWithLooper; +import android.view.WindowManager; + +import androidx.test.filters.SmallTest; import com.android.internal.R; import com.android.systemui.SysuiTestCase; @@ -97,6 +101,8 @@ public class AuthControllerTest extends SysuiTestCase { @Mock private ActivityTaskManager mActivityTaskManager; @Mock + private WindowManager mWindowManager; + @Mock private FingerprintManager mFingerprintManager; @Mock private FaceManager mFaceManager; @@ -149,7 +155,7 @@ public class AuthControllerTest extends SysuiTestCase { when(mFingerprintManager.getSensorPropertiesInternal()).thenReturn(props); mAuthController = new TestableAuthController(context, mCommandQueue, - mActivityTaskManager, mFingerprintManager, mFaceManager, + mActivityTaskManager, mWindowManager, mFingerprintManager, mFaceManager, () -> mUdfpsController, () -> mSidefpsController); mAuthController.start(); @@ -536,6 +542,17 @@ public class AuthControllerTest extends SysuiTestCase { verify(mUdfpsController).onAodInterrupt(eq(pos), eq(pos), eq(majorMinor), eq(majorMinor)); } + @Test + public void testSubscribesToOrientationChangesWhenShowingDialog() { + assertFalse(mAuthController.mOrientationListener.getEnabled()); + + showDialog(new int[]{1} /* sensorIds */, false /* credentialAllowed */); + assertTrue(mAuthController.mOrientationListener.getEnabled()); + + mAuthController.hideAuthenticationDialog(); + assertFalse(mAuthController.mOrientationListener.getEnabled()); + } + // Helpers private void showDialog(int[] sensorIds, boolean credentialAllowed) { @@ -576,13 +593,15 @@ public class AuthControllerTest extends SysuiTestCase { private int mBuildCount = 0; private PromptInfo mLastBiometricPromptInfo; - TestableAuthController(Context context, CommandQueue commandQueue, + TestableAuthController(Context context, + CommandQueue commandQueue, ActivityTaskManager activityTaskManager, + WindowManager windowManager, FingerprintManager fingerprintManager, FaceManager faceManager, Provider<UdfpsController> udfpsControllerFactory, Provider<SidefpsController> sidefpsControllerFactory) { - super(context, commandQueue, activityTaskManager, + super(context, commandQueue, activityTaskManager, windowManager, fingerprintManager, faceManager, udfpsControllerFactory, sidefpsControllerFactory); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/SidefpsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/SidefpsControllerTest.kt new file mode 100644 index 000000000000..7019a4bbb08c --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/SidefpsControllerTest.kt @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.biometrics + +import android.hardware.biometrics.SensorProperties +import android.hardware.display.DisplayManagerGlobal +import android.hardware.fingerprint.FingerprintManager +import android.hardware.fingerprint.FingerprintSensorProperties +import android.hardware.fingerprint.FingerprintSensorPropertiesInternal +import android.hardware.fingerprint.ISidefpsController +import android.testing.AndroidTestingRunner +import android.testing.TestableLooper +import android.view.Display +import android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS +import android.view.DisplayInfo +import android.view.LayoutInflater +import android.view.WindowManager +import androidx.test.filters.SmallTest +import com.android.systemui.R +import com.android.systemui.SysuiTestCase +import com.android.systemui.util.concurrency.FakeExecutor +import com.android.systemui.util.time.FakeSystemClock +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentCaptor +import org.mockito.Mock +import org.mockito.Mockito.`when` +import org.mockito.Mockito.verify +import org.mockito.junit.MockitoJUnit + +private const val DISPLAY_ID = 2 +private const val SENSOR_ID = 1 + +@SmallTest +@RunWith(AndroidTestingRunner::class) +@TestableLooper.RunWithLooper +class SidefpsControllerTest : SysuiTestCase() { + + @JvmField @Rule + var rule = MockitoJUnit.rule() + + @Mock + lateinit var layoutInflater: LayoutInflater + @Mock + lateinit var fingerprintManager: FingerprintManager + @Mock + lateinit var windowManager: WindowManager + @Mock + lateinit var sidefpsView: SidefpsView + + private val executor = FakeExecutor(FakeSystemClock()) + private lateinit var overlayController: ISidefpsController + private lateinit var sideFpsController: SidefpsController + + @Before + fun setup() { + `when`(layoutInflater.inflate(R.layout.sidefps_view, null, false)).thenReturn(sidefpsView) + `when`(fingerprintManager.sensorPropertiesInternal).thenReturn( + listOf( + FingerprintSensorPropertiesInternal( + SENSOR_ID, + SensorProperties.STRENGTH_STRONG, + 5 /* maxEnrollmentsPerUser */, + listOf() /* componentInfo */, + FingerprintSensorProperties.TYPE_POWER_BUTTON, + true /* resetLockoutRequiresHardwareAuthToken */ + ) + ) + ) + `when`(windowManager.defaultDisplay).thenReturn( + Display( + DisplayManagerGlobal.getInstance(), + DISPLAY_ID, + DisplayInfo(), + DEFAULT_DISPLAY_ADJUSTMENTS + ) + ) + + sideFpsController = SidefpsController( + mContext, layoutInflater, fingerprintManager, windowManager, executor + ) + + overlayController = ArgumentCaptor.forClass(ISidefpsController::class.java).apply { + verify(fingerprintManager).setSidefpsController(capture()) + }.value + } + + @Test + fun testSubscribesToOrientationChangesWhenShowingOverlay() { + assertThat(sideFpsController.mOrientationListener.enabled).isFalse() + + overlayController.show() + executor.runAllReady() + assertThat(sideFpsController.mOrientationListener.enabled).isTrue() + + overlayController.hide() + executor.runAllReady() + assertThat(sideFpsController.mOrientationListener.enabled).isFalse() + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java index 25722e1c956b..d8d3676d4fa2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java @@ -17,6 +17,8 @@ package com.android.systemui.biometrics; import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyFloat; @@ -236,6 +238,22 @@ public class UdfpsControllerTest extends SysuiTestCase { } @Test + public void testSubscribesToOrientationChangesWhenShowingOverlay() throws Exception { + assertFalse(mUdfpsController.mOrientationListener.getEnabled()); + + mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID, + IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD, mUdfpsOverlayControllerCallback); + mFgExecutor.runAllReady(); + + assertTrue(mUdfpsController.mOrientationListener.getEnabled()); + + mOverlayController.hideUdfpsOverlay(TEST_UDFPS_SENSOR_ID); + mFgExecutor.runAllReady(); + + assertFalse(mUdfpsController.mOrientationListener.getEnabled()); + } + + @Test public void fingerDown() throws RemoteException { // Configure UdfpsView to accept the ACTION_DOWN event when(mUdfpsView.isIlluminationRequested()).thenReturn(false); diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java index 546038ec3030..b2a9e8209495 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java @@ -39,7 +39,6 @@ import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.testing.FakeMetricsLogger; import com.android.systemui.SysuiTestCase; import com.android.systemui.classifier.FalsingDataProvider.GestureFinalizedListener; -import com.android.systemui.dock.DockManagerFake; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.time.FakeSystemClock; @@ -62,7 +61,6 @@ public class BrightLineClassifierTest extends SysuiTestCase { private BrightLineFalsingManager mBrightLineFalsingManager; @Mock private FalsingDataProvider mFalsingDataProvider; - private final DockManagerFake mDockManager = new DockManagerFake(); private final MetricsLogger mMetricsLogger = new FakeMetricsLogger(); private final Set<FalsingClassifier> mClassifiers = new HashSet<>(); @Mock @@ -102,7 +100,7 @@ public class BrightLineClassifierTest extends SysuiTestCase { mClassifiers.add(mClassifierB); when(mFalsingDataProvider.getRecentMotionEvents()).thenReturn(mMotionEventList); when(mKeyguardStateController.isShowing()).thenReturn(true); - mBrightLineFalsingManager = new BrightLineFalsingManager(mFalsingDataProvider, mDockManager, + mBrightLineFalsingManager = new BrightLineFalsingManager(mFalsingDataProvider, mMetricsLogger, mClassifiers, mSingleTapClassfier, mDoubleTapClassifier, mHistoryTracker, mKeyguardStateController, mAccessibilityManager, false); @@ -168,7 +166,7 @@ public class BrightLineClassifierTest extends SysuiTestCase { // Even when the classifiers report a false, we should allow. when(mClassifierA.classifyGesture(anyInt(), anyDouble(), anyDouble())) .thenReturn(mPassedResult); - mDockManager.setIsDocked(true); + when(mFalsingDataProvider.isDocked()).thenReturn(true); assertThat(mBrightLineFalsingManager.isFalseTouch(0)).isFalse(); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineFalsingManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineFalsingManagerTest.java index 86243b53804e..c4f480d7e7aa 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineFalsingManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineFalsingManagerTest.java @@ -32,7 +32,6 @@ import androidx.test.filters.SmallTest; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.testing.FakeMetricsLogger; import com.android.systemui.SysuiTestCase; -import com.android.systemui.dock.DockManagerFake; import com.android.systemui.statusbar.policy.KeyguardStateController; import org.junit.Before; @@ -52,7 +51,6 @@ public class BrightLineFalsingManagerTest extends SysuiTestCase { private BrightLineFalsingManager mBrightLineFalsingManager; @Mock private FalsingDataProvider mFalsingDataProvider; - private final DockManagerFake mDockManager = new DockManagerFake(); private final MetricsLogger mMetricsLogger = new FakeMetricsLogger(); private final Set<FalsingClassifier> mClassifiers = new HashSet<>(); @Mock @@ -84,7 +82,7 @@ public class BrightLineFalsingManagerTest extends SysuiTestCase { mClassifiers.add(mClassifierA); when(mFalsingDataProvider.getRecentMotionEvents()).thenReturn(mMotionEventList); when(mKeyguardStateController.isShowing()).thenReturn(true); - mBrightLineFalsingManager = new BrightLineFalsingManager(mFalsingDataProvider, mDockManager, + mBrightLineFalsingManager = new BrightLineFalsingManager(mFalsingDataProvider, mMetricsLogger, mClassifiers, mSingleTapClassifier, mDoubleTapClassifier, mHistoryTracker, mKeyguardStateController, mAccessibilityManager, false); diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/ClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/ClassifierTest.java index 7d6ff34bb954..5fa7214f07ff 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/ClassifierTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/ClassifierTest.java @@ -19,30 +19,35 @@ package com.android.systemui.classifier; import android.util.DisplayMetrics; import android.view.MotionEvent; -import com.android.systemui.utils.leaks.FakeBatteryController; -import com.android.systemui.utils.leaks.LeakCheckedTest; +import com.android.systemui.SysuiTestCase; +import com.android.systemui.dock.DockManagerFake; +import com.android.systemui.statusbar.policy.BatteryController; import org.junit.After; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; import java.util.ArrayList; import java.util.List; -public class ClassifierTest extends LeakCheckedTest { +public class ClassifierTest extends SysuiTestCase { private FalsingDataProvider mDataProvider; - private List<MotionEvent> mMotionEvents = new ArrayList<>(); + private final List<MotionEvent> mMotionEvents = new ArrayList<>(); private float mOffsetX = 0; private float mOffsetY = 0; - private FakeBatteryController mFakeBatteryController; + @Mock + private BatteryController mBatteryController; + private final DockManagerFake mDockManager = new DockManagerFake(); public void setup() { + MockitoAnnotations.initMocks(this); DisplayMetrics displayMetrics = new DisplayMetrics(); displayMetrics.xdpi = 100; displayMetrics.ydpi = 100; displayMetrics.widthPixels = 1000; displayMetrics.heightPixels = 1000; - mFakeBatteryController = new FakeBatteryController(getLeakCheck()); - mDataProvider = new FalsingDataProvider(displayMetrics, mFakeBatteryController); + mDataProvider = new FalsingDataProvider(displayMetrics, mBatteryController, mDockManager); } @After @@ -54,10 +59,6 @@ public class ClassifierTest extends LeakCheckedTest { return mDataProvider; } - FakeBatteryController getFakeBatteryController() { - return mFakeBatteryController; - } - protected void setOffsetX(float offsetX) { mOffsetX = offsetX; } diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingCollectorImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingCollectorImplTest.java index 3c41216949c2..d99a5531d353 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingCollectorImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingCollectorImplTest.java @@ -32,9 +32,12 @@ import androidx.test.filters.SmallTest; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.SysuiTestCase; +import com.android.systemui.dock.DockManager; +import com.android.systemui.dock.DockManagerFake; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.SysuiStatusBarStateController; +import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.sensors.ProximitySensor; @@ -67,6 +70,9 @@ public class FalsingCollectorImplTest extends SysuiTestCase { private SysuiStatusBarStateController mStatusBarStateController; @Mock private KeyguardStateController mKeyguardStateController; + @Mock + private BatteryController mBatteryController; + private final DockManagerFake mDockManager = new DockManagerFake(); private final FakeSystemClock mFakeSystemClock = new FakeSystemClock(); private final FakeExecutor mFakeExecutor = new FakeExecutor(mFakeSystemClock); @@ -79,8 +85,8 @@ public class FalsingCollectorImplTest extends SysuiTestCase { mFalsingCollector = new FalsingCollectorImpl(mFalsingDataProvider, mFalsingManager, mKeyguardUpdateMonitor, mHistoryTracker, mProximitySensor, - mStatusBarStateController, mKeyguardStateController, mFakeExecutor, - mFakeSystemClock); + mStatusBarStateController, mKeyguardStateController, mBatteryController, + mDockManager, mFakeExecutor, mFakeSystemClock); } @Test @@ -91,9 +97,32 @@ public class FalsingCollectorImplTest extends SysuiTestCase { @Test public void testNoProximityWhenWirelessCharging() { - when(mFalsingDataProvider.isWirelessCharging()).thenReturn(true); - mFalsingCollector.onScreenTurningOn(); - verify(mProximitySensor, never()).register(any(ThresholdSensor.Listener.class)); + ArgumentCaptor<BatteryController.BatteryStateChangeCallback> batteryCallbackCaptor = + ArgumentCaptor.forClass(BatteryController.BatteryStateChangeCallback.class); + verify(mBatteryController).addCallback(batteryCallbackCaptor.capture()); + batteryCallbackCaptor.getValue().onWirelessChargingChanged(true); + verify(mProximitySensor).pause(); + } + + @Test + public void testProximityWhenOffWirelessCharging() { + ArgumentCaptor<BatteryController.BatteryStateChangeCallback> batteryCallbackCaptor = + ArgumentCaptor.forClass(BatteryController.BatteryStateChangeCallback.class); + verify(mBatteryController).addCallback(batteryCallbackCaptor.capture()); + batteryCallbackCaptor.getValue().onWirelessChargingChanged(false); + verify(mProximitySensor).resume(); + } + + @Test + public void testNoProximityWhenDocked() { + mDockManager.setDockEvent(DockManager.STATE_DOCKED); + verify(mProximitySensor).pause(); + } + + @Test + public void testProximityWhenUndocked() { + mDockManager.setDockEvent(DockManager.STATE_NONE); + verify(mProximitySensor).resume(); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingDataProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingDataProviderTest.java index 1fe694e97bcf..5dc607fd342b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingDataProviderTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingDataProviderTest.java @@ -22,6 +22,7 @@ import static org.mockito.ArgumentMatchers.anyLong; 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.testing.AndroidTestingRunner; import android.util.DisplayMetrics; @@ -30,12 +31,15 @@ import android.view.MotionEvent; import androidx.test.filters.SmallTest; import com.android.systemui.classifier.FalsingDataProvider.GestureFinalizedListener; -import com.android.systemui.utils.leaks.FakeBatteryController; +import com.android.systemui.dock.DockManagerFake; +import com.android.systemui.statusbar.policy.BatteryController; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; import java.util.List; @@ -43,19 +47,21 @@ import java.util.List; @RunWith(AndroidTestingRunner.class) public class FalsingDataProviderTest extends ClassifierTest { - private FakeBatteryController mFakeBatteryController; private FalsingDataProvider mDataProvider; + @Mock + private BatteryController mBatteryController; + private final DockManagerFake mDockManager = new DockManagerFake(); @Before public void setup() { super.setup(); - mFakeBatteryController = new FakeBatteryController(getLeakCheck()); + MockitoAnnotations.initMocks(this); DisplayMetrics displayMetrics = new DisplayMetrics(); displayMetrics.xdpi = 100; displayMetrics.ydpi = 100; displayMetrics.widthPixels = 1000; displayMetrics.heightPixels = 1000; - mDataProvider = new FalsingDataProvider(displayMetrics, mFakeBatteryController); + mDataProvider = new FalsingDataProvider(displayMetrics, mBatteryController, mDockManager); } @After @@ -250,10 +256,17 @@ public class FalsingDataProviderTest extends ClassifierTest { @Test public void test_isWirelessCharging() { - assertThat(mDataProvider.isWirelessCharging()).isFalse(); + assertThat(mDataProvider.isDocked()).isFalse(); - mFakeBatteryController.setWirelessCharging(true); - assertThat(mDataProvider.isWirelessCharging()).isTrue(); + when(mBatteryController.isWirelessCharging()).thenReturn(true); + assertThat(mDataProvider.isDocked()).isTrue(); + } + + @Test + public void test_isDocked() { + assertThat(mDataProvider.isDocked()).isFalse(); + mDockManager.setIsDocked(true); + assertThat(mDataProvider.isDocked()).isTrue(); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarRotationContextTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarRotationContextTest.java index b9919767d63f..a6ff2e8d2e15 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarRotationContextTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarRotationContextTest.java @@ -59,7 +59,16 @@ public class NavigationBarRotationContextTest extends SysuiTestCase { final View view = new View(mContext); mRotationButton = mock(RotationButton.class); mRotationButtonController = new RotationButtonController(mContext, 0, 0); - mRotationButtonController.setRotationButton(mRotationButton, (visibility) -> {}); + mRotationButtonController.setRotationButton(mRotationButton, + new RotationButton.RotationButtonUpdatesCallback() { + @Override + public void onVisibilityChanged(boolean isVisible) { + } + + @Override + public void onPositionChanged() { + } + }); // Due to a mockito issue, only spy the object after setting the initial state mRotationButtonController = spy(mRotationButtonController); doReturn(view).when(mRotationButton).getCurrentView(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/gestural/FloatingRotationButtonPositionCalculatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/gestural/FloatingRotationButtonPositionCalculatorTest.kt new file mode 100644 index 000000000000..0a2000107053 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/gestural/FloatingRotationButtonPositionCalculatorTest.kt @@ -0,0 +1,127 @@ +package com.android.systemui.navigationbar.gestural + +import android.view.Gravity +import android.view.Surface +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.navigationbar.gestural.FloatingRotationButtonPositionCalculator.Position +import com.google.common.truth.Truth.assertThat +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.Parameterized + +@RunWith(Parameterized::class) +@SmallTest +internal class FloatingRotationButtonPositionCalculatorTest(private val testCase: TestCase) + : SysuiTestCase() { + + private val calculator = FloatingRotationButtonPositionCalculator( + MARGIN_DEFAULT, MARGIN_TASKBAR_LEFT, MARGIN_TASKBAR_BOTTOM + ) + + @Test + fun calculatePosition() { + val position = calculator.calculatePosition( + testCase.rotation, + testCase.taskbarVisible, + testCase.taskbarStashed + ) + + assertThat(position).isEqualTo(testCase.expectedPosition) + } + + internal class TestCase( + val rotation: Int, + val taskbarVisible: Boolean, + val taskbarStashed: Boolean, + val expectedPosition: Position + ) { + override fun toString(): String = + "when rotation = $rotation, " + + "taskbarVisible = $taskbarVisible, " + + "taskbarStashed = $taskbarStashed - " + + "expected $expectedPosition" + } + + companion object { + @Parameterized.Parameters(name = "{0}") + @JvmStatic + fun getParams(): Collection<TestCase> = + listOf( + TestCase( + rotation = Surface.ROTATION_0, + taskbarVisible = false, + taskbarStashed = false, + expectedPosition = Position( + gravity = Gravity.BOTTOM or Gravity.LEFT, + translationX = MARGIN_DEFAULT, + translationY = -MARGIN_DEFAULT + ) + ), + TestCase( + rotation = Surface.ROTATION_90, + taskbarVisible = false, + taskbarStashed = false, + expectedPosition = Position( + gravity = Gravity.BOTTOM or Gravity.RIGHT, + translationX = -MARGIN_DEFAULT, + translationY = -MARGIN_DEFAULT + ) + ), + TestCase( + rotation = Surface.ROTATION_180, + taskbarVisible = false, + taskbarStashed = false, + expectedPosition = Position( + gravity = Gravity.TOP or Gravity.RIGHT, + translationX = -MARGIN_DEFAULT, + translationY = MARGIN_DEFAULT + ) + ), + TestCase( + rotation = Surface.ROTATION_270, + taskbarVisible = false, + taskbarStashed = false, + expectedPosition = Position( + gravity = Gravity.TOP or Gravity.LEFT, + translationX = MARGIN_DEFAULT, + translationY = MARGIN_DEFAULT + ) + ), + TestCase( + rotation = Surface.ROTATION_0, + taskbarVisible = true, + taskbarStashed = false, + expectedPosition = Position( + gravity = Gravity.BOTTOM or Gravity.LEFT, + translationX = MARGIN_TASKBAR_LEFT, + translationY = -MARGIN_TASKBAR_BOTTOM + ) + ), + TestCase( + rotation = Surface.ROTATION_0, + taskbarVisible = true, + taskbarStashed = true, + expectedPosition = Position( + gravity = Gravity.BOTTOM or Gravity.LEFT, + translationX = MARGIN_DEFAULT, + translationY = -MARGIN_DEFAULT + ) + ), + TestCase( + rotation = Surface.ROTATION_90, + taskbarVisible = true, + taskbarStashed = false, + expectedPosition = Position( + gravity = Gravity.BOTTOM or Gravity.RIGHT, + translationX = -MARGIN_TASKBAR_LEFT, + translationY = -MARGIN_TASKBAR_BOTTOM + ) + ) + ) + + private const val MARGIN_DEFAULT = 10 + private const val MARGIN_TASKBAR_LEFT = 20 + private const val MARGIN_TASKBAR_BOTTOM = 30 + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleTileViewHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleTileViewHelperTest.java index c818da8d029f..b4b459752bc2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleTileViewHelperTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleTileViewHelperTest.java @@ -289,6 +289,8 @@ public class PeopleTileViewHelperTest extends SysuiTestCase { assertEquals(View.GONE, result.findViewById(R.id.last_interaction).getVisibility()); // Has availability. assertEquals(View.VISIBLE, result.findViewById(R.id.availability).getVisibility()); + assertEquals(result.findViewById(R.id.availability).getContentDescription(), + mContext.getString(R.string.person_available)); // Has person icon. assertEquals(View.VISIBLE, result.findViewById(R.id.person_icon).getVisibility()); // No status. @@ -334,6 +336,8 @@ public class PeopleTileViewHelperTest extends SysuiTestCase { assertEquals(View.GONE, largeResult.findViewById(R.id.last_interaction).getVisibility()); // Has availability. assertEquals(View.VISIBLE, largeResult.findViewById(R.id.availability).getVisibility()); + assertEquals(largeResult.findViewById(R.id.availability).getContentDescription(), + mContext.getString(R.string.person_available)); // Shows person icon. assertEquals(View.VISIBLE, largeResult.findViewById(R.id.person_icon).getVisibility()); // No status. diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java index 05bef4c2aeb7..24c189a85327 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java @@ -1125,7 +1125,8 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { new PeopleTileKey(SHORTCUT_ID, 0, TEST_PACKAGE_A)); when(mIPeopleManager.getConversation(TEST_PACKAGE_A, 0, SHORTCUT_ID)).thenReturn(channel); PeopleTileKey key = new PeopleTileKey(SHORTCUT_ID, 0, TEST_PACKAGE_A); - PeopleSpaceTile tile = mManager.getTileFromPersistentStorage(key, WIDGET_ID_WITH_SHORTCUT); + PeopleSpaceTile tile = mManager + .getTileFromPersistentStorage(key, WIDGET_ID_WITH_SHORTCUT, true); assertThat(tile.getId()).isEqualTo(key.getShortcutId()); } @@ -1133,7 +1134,8 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { public void testGetPeopleTileFromPersistentStorageNoConversation() throws Exception { when(mIPeopleManager.getConversation(TEST_PACKAGE_A, 0, SHORTCUT_ID)).thenReturn(null); PeopleTileKey key = new PeopleTileKey(SHORTCUT_ID, 0, TEST_PACKAGE_A); - PeopleSpaceTile tile = mManager.getTileFromPersistentStorage(key, WIDGET_ID_WITH_SHORTCUT); + PeopleSpaceTile tile = mManager + .getTileFromPersistentStorage(key, WIDGET_ID_WITH_SHORTCUT, false); assertThat(tile).isNull(); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSDetailTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSDetailTest.java index 75cf8550518b..c2bd024f0375 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSDetailTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSDetailTest.java @@ -41,6 +41,7 @@ import com.android.internal.logging.testing.UiEventLoggerFake; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.DetailAdapter; import org.junit.After; @@ -76,7 +77,8 @@ public class QSDetailTest extends SysuiTestCase { mQsPanelController = mock(QSPanelController.class); mQuickHeader = mock(QuickStatusBarHeader.class); - mQsDetail.setQsPanel(mQsPanelController, mQuickHeader, mock(QSFooter.class)); + mQsDetail.setQsPanel(mQsPanelController, mQuickHeader, mock(QSFooter.class), + mock(FalsingManager.class)); mQsDetail.mClipper = mock(QSDetailClipper.class); mMockDetailAdapter = mock(DetailAdapter.class); diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java index 2ae4cbe17ac6..c40977b31e73 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java @@ -44,6 +44,7 @@ import com.android.systemui.SysuiBaseFragmentTest; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dump.DumpManager; import com.android.systemui.media.MediaHost; +import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.dagger.QSFragmentComponent; import com.android.systemui.qs.external.CustomTileStatePersister; @@ -92,6 +93,8 @@ public class QSFragmentTest extends SysuiBaseFragmentTest { private MediaHost mQQSMediaHost; @Mock private FeatureFlags mFeatureFlags; + @Mock + private FalsingManager mFalsingManager; public QSFragmentTest() { super(QSFragment.class); @@ -182,6 +185,7 @@ public class QSFragmentTest extends SysuiBaseFragmentTest { mQSMediaHost, mQQSMediaHost, mQsComponentFactory, - mFeatureFlags); + mFeatureFlags, + mFalsingManager); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java index a70c2be4954e..17797b70c4af 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java @@ -30,6 +30,7 @@ import static junit.framework.TestCase.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; @@ -256,6 +257,19 @@ public class QuickAccessWalletTileTest extends SysuiTestCase { } @Test + public void testGetServiceLabelUnsafe_recreateWalletClient() { + doAnswer(invocation -> { + throw new Exception("Bad service label."); + }).when(mQuickAccessWalletClient).getServiceLabel(); + + QSTile.State state = new QSTile.State(); + + mTile.handleUpdateState(state, null); + + verify(mController).reCreateWalletClient(); + } + + @Test public void testHandleUpdateState_updateLabelAndIcon() { QSTile.State state = new QSTile.State(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java index 21c6292c151f..d5a2919880ef 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java @@ -33,6 +33,7 @@ import android.hardware.biometrics.IBiometricSysuiReceiver; import android.hardware.biometrics.PromptInfo; import android.hardware.fingerprint.IUdfpsHbmListener; import android.os.Bundle; +import android.view.InsetsState; import android.view.WindowInsetsController.Appearance; import android.view.WindowInsetsController.Behavior; @@ -124,24 +125,25 @@ public class CommandQueueTest extends SysuiTestCase { public void testOnSystemBarAttributesChanged() { doTestOnSystemBarAttributesChanged(DEFAULT_DISPLAY, 1, new AppearanceRegion[]{new AppearanceRegion(2, new Rect())}, false, - BEHAVIOR_DEFAULT, false); + BEHAVIOR_DEFAULT, new InsetsState(), "test"); } @Test public void testOnSystemBarAttributesChangedForSecondaryDisplay() { doTestOnSystemBarAttributesChanged(SECONDARY_DISPLAY, 1, new AppearanceRegion[]{new AppearanceRegion(2, new Rect())}, false, - BEHAVIOR_DEFAULT, false); + BEHAVIOR_DEFAULT, new InsetsState(), "test"); } private void doTestOnSystemBarAttributesChanged(int displayId, @Appearance int appearance, AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme, - @Behavior int behavior, boolean isFullscreen) { + @Behavior int behavior, InsetsState requestedState, String packageName) { mCommandQueue.onSystemBarAttributesChanged(displayId, appearance, appearanceRegions, - navbarColorManagedByIme, behavior, isFullscreen); + navbarColorManagedByIme, behavior, requestedState, packageName); waitForIdleSync(); verify(mCallbacks).onSystemBarAttributesChanged(eq(displayId), eq(appearance), - eq(appearanceRegions), eq(navbarColorManagedByIme), eq(behavior), eq(isFullscreen)); + eq(appearanceRegions), eq(navbarColorManagedByIme), eq(behavior), + eq(requestedState), eq(packageName)); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java index 7c819f5c5ba4..85ea52b6af6a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java @@ -39,6 +39,7 @@ import android.graphics.Bitmap; import android.graphics.Color; import android.graphics.drawable.Icon; import android.os.UserHandle; +import android.service.notification.StatusBarNotification; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -131,4 +132,19 @@ public class StatusBarIconViewTest extends SysuiTestCase { icon, 0, 0, ""); assertFalse(mIconView.set(largeIcon)); } + + @Test + public void testNullNotifInfo() { + Bitmap bitmap = Bitmap.createBitmap(60, 60, Bitmap.Config.ARGB_8888); + Icon icon = Icon.createWithBitmap(bitmap); + StatusBarIcon largeIcon = new StatusBarIcon(UserHandle.ALL, "mockPackage", + icon, 0, 0, ""); + mIconView.setNotification(mock(StatusBarNotification.class)); + mIconView.getIcon(largeIcon); + // no crash? good + + mIconView.setNotification(null); + mIconView.getIcon(largeIcon); + // no crash? good + } }
\ No newline at end of file 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 04d7b7261ba7..3f35063fea6d 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 @@ -63,7 +63,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.FooterView; -import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.KeyguardBypassEnabledProvider; +import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.ShadeController; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController; @@ -100,7 +100,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { @Mock private NotificationRemoteInputManager mRemoteInputManager; @Mock private RemoteInputController mRemoteInputController; @Mock private NotificationRoundnessManager mNotificationRoundnessManager; - @Mock private KeyguardBypassEnabledProvider mKeyguardBypassEnabledProvider; + @Mock private KeyguardBypassController mBypassController; @Mock private NotificationSectionsManager mNotificationSectionsManager; @Mock private NotificationSection mNotificationSection; @Mock private SysuiStatusBarStateController mStatusBarStateController; @@ -132,7 +132,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { when(mRemoteInputManager.getController()).thenReturn(mRemoteInputController); // Interact with real instance of AmbientState. - mAmbientState = new AmbientState(mContext, mNotificationSectionsManager); + mAmbientState = new AmbientState(mContext, mNotificationSectionsManager, mBypassController); // The actual class under test. You may need to work with this class directly when // testing anonymous class members of mStackScroller, like mMenuEventListener, @@ -148,8 +148,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { mAmbientState, mFeatureFlags, mUnlockedScreenOffAnimationController); - mStackScrollerInternal.initView(getContext(), mKeyguardBypassEnabledProvider, - mNotificationSwipeHelper); + mStackScrollerInternal.initView(getContext(), mNotificationSwipeHelper); mStackScroller = spy(mStackScrollerInternal); mStackScroller.setShelfController(notificationShelfController); mStackScroller.setStatusBar(mBar); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java index b54f9234188f..60f0b68acac3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java @@ -40,6 +40,7 @@ import android.testing.TestableResources; import com.android.internal.logging.MetricsLogger; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.SysuiTestCase; +import com.android.systemui.biometrics.AuthController; import com.android.systemui.dump.DumpManager; import com.android.systemui.keyguard.KeyguardViewMediator; import com.android.systemui.keyguard.ScreenLifecycle; @@ -89,6 +90,8 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase { @Mock private KeyguardBypassController mKeyguardBypassController; @Mock + private AuthController mAuthController; + @Mock private DozeParameters mDozeParameters; @Mock private MetricsLogger mMetricsLogger; @@ -109,6 +112,7 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase { when(mKeyguardStateController.isFaceAuthEnabled()).thenReturn(true); when(mKeyguardBypassController.onBiometricAuthenticated(any(), anyBoolean())) .thenReturn(true); + when(mAuthController.isUdfpsFingerDown()).thenReturn(false); when(mKeyguardBypassController.canPlaySubtleWindowAnimations()).thenReturn(true); mContext.addMockSystemService(PowerManager.class, mPowerManager); mDependency.injectTestDependency(NotificationMediaManager.class, mMediaManager); @@ -118,7 +122,8 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase { mNotificationShadeWindowController, mKeyguardStateController, mHandler, mUpdateMonitor, res.getResources(), mKeyguardBypassController, mDozeParameters, mMetricsLogger, mDumpManager, mPowerManager, - mNotificationMediaManager, mWakefulnessLifecycle, mScreenLifecycle); + mNotificationMediaManager, mWakefulnessLifecycle, mScreenLifecycle, + mAuthController); mBiometricUnlockController.setKeyguardViewController(mStatusBarKeyguardViewManager); mBiometricUnlockController.setBiometricModeListener(mBiometricModeListener); } @@ -229,6 +234,25 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase { } @Test + public void onBiometricAuthenticated_whenFace_andNonBypassAndUdfps_dismissKeyguard() { + when(mKeyguardBypassController.getBypassEnabled()).thenReturn(false); + when(mAuthController.isUdfpsFingerDown()).thenReturn(true); + mBiometricUnlockController.setKeyguardViewController(mStatusBarKeyguardViewManager); + + when(mUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true); + // the value of isStrongBiometric doesn't matter here since we only care about the returned + // value of isUnlockingWithBiometricAllowed() + mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT, + BiometricSourceType.FACE, true /* isStrongBiometric */); + + verify(mShadeController, never()).animateCollapsePanels(anyInt(), anyBoolean(), + anyBoolean(), anyFloat()); + verify(mStatusBarKeyguardViewManager).notifyKeyguardAuthenticated(eq(false)); + assertThat(mBiometricUnlockController.getMode()) + .isEqualTo(BiometricUnlockController.MODE_UNLOCK_FADING); + } + + @Test public void onBiometricAuthenticated_whenFace_andBypass_encrypted_showBouncer() { reset(mUpdateMonitor); when(mKeyguardBypassController.getBypassEnabled()).thenReturn(true); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightsOutNotifControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightsOutNotifControllerTest.java index cdfab1eec609..c3adee95df20 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightsOutNotifControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightsOutNotifControllerTest.java @@ -102,7 +102,8 @@ public class LightsOutNotifControllerTest extends SysuiTestCase { null /* appearanceRegions */, false /* navbarColorManagedByIme */, BEHAVIOR_DEFAULT, - false /* isFullscreen */); + null /* requestedState */, + null /* packageName */); assertTrue(mLightsOutNotifController.areLightsOut()); } @@ -114,7 +115,8 @@ public class LightsOutNotifControllerTest extends SysuiTestCase { null /* appearanceRegions */, false /* navbarColorManagedByIme */, BEHAVIOR_DEFAULT, - false /* isFullscreen */); + null /* requestedState */, + null /* packageName */); assertFalse(mLightsOutNotifController.areLightsOut()); } @@ -144,7 +146,8 @@ public class LightsOutNotifControllerTest extends SysuiTestCase { null /* appearanceRegions */, false /* navbarColorManagedByIme */, BEHAVIOR_DEFAULT, - false /* isFullscreen */); + null /* requestedState */, + null /* packageName */); // THEN we should show dot assertTrue(mLightsOutNotifController.shouldShowDot()); @@ -163,7 +166,8 @@ public class LightsOutNotifControllerTest extends SysuiTestCase { null /* appearanceRegions */, false /* navbarColorManagedByIme */, BEHAVIOR_DEFAULT, - false /* isFullscreen */); + null /* requestedState */, + null /* packageName */); // THEN we shouldn't show the dot assertFalse(mLightsOutNotifController.shouldShowDot()); @@ -182,7 +186,8 @@ public class LightsOutNotifControllerTest extends SysuiTestCase { null /* appearanceRegions */, false /* navbarColorManagedByIme */, BEHAVIOR_DEFAULT, - false /* isFullscreen */); + null /* requestedState */, + null /* packageName */); // THEN we shouldn't show the dot assertFalse(mLightsOutNotifController.shouldShowDot()); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java index 1d4cbdc959c1..c39a9061f95d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java @@ -16,11 +16,15 @@ package com.android.systemui.statusbar.phone; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyFloat; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.clearInvocations; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; @@ -35,12 +39,15 @@ import android.view.ViewGroup; import androidx.test.filters.SmallTest; import com.android.internal.widget.LockPatternUtils; +import com.android.keyguard.KeyguardMessageArea; +import com.android.keyguard.KeyguardMessageAreaController; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.ViewMediatorCallback; import com.android.systemui.SysuiTestCase; import com.android.systemui.dock.DockManager; import com.android.systemui.keyguard.DismissCallbackRegistry; import com.android.systemui.keyguard.FaceAuthScreenBrightnessController; +import com.android.systemui.keyguard.WakefulnessLifecycle; import com.android.systemui.navigationbar.NavigationModeController; import com.android.systemui.plugins.ActivityStarter.OnDismissAction; import com.android.systemui.statusbar.NotificationMediaManager; @@ -89,8 +96,15 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { @Mock private KeyguardBouncer.Factory mKeyguardBouncerFactory; @Mock + private KeyguardMessageAreaController.Factory mKeyguardMessageAreaFactory; + @Mock private KeyguardBouncer mBouncer; + @Mock + private UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController; + @Mock + private KeyguardMessageArea mKeyguardMessageArea; + private WakefulnessLifecycle mWakefulnessLifecycle; private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; @Before @@ -101,6 +115,8 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { any(KeyguardBouncer.BouncerExpansionCallback.class))) .thenReturn(mBouncer); + when(mContainer.findViewById(anyInt())).thenReturn(mKeyguardMessageArea); + mWakefulnessLifecycle = new WakefulnessLifecycle(getContext(), null); mStatusBarKeyguardViewManager = new StatusBarKeyguardViewManager( getContext(), mViewMediatorCallback, @@ -114,7 +130,10 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { mKeyguardStateController, Optional.of(mFaceAuthScreenBrightnessController), mock(NotificationMediaManager.class), - mKeyguardBouncerFactory); + mKeyguardBouncerFactory, + mWakefulnessLifecycle, + mUnlockedScreenOffAnimationController, + mKeyguardMessageAreaFactory); mStatusBarKeyguardViewManager.registerStatusBar(mStatusBar, mContainer, mNotificationPanelView, mBiometrucUnlockController, mNotificationContainer, mBypassController); @@ -280,4 +299,18 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { verify(mBouncer).updateKeyguardPosition(1.0f); } + + @Test + public void testNavBarHiddenWhenSleepAnimationStarts() { + mStatusBarKeyguardViewManager.hide(0 /* startTime */, 0 /* fadeoutDuration */); + assertTrue(mStatusBarKeyguardViewManager.isNavBarVisible()); + + // Verify that the nav bar is hidden when the screen off animation starts + doReturn(true).when(mUnlockedScreenOffAnimationController).isScreenOffAnimationPlaying(); + mWakefulnessLifecycle.dispatchFinishedGoingToSleep(); + assertFalse(mStatusBarKeyguardViewManager.isNavBarVisible()); + + mWakefulnessLifecycle.dispatchFinishedWakingUp(); + assertTrue(mStatusBarKeyguardViewManager.isNavBarVisible()); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java index cbc7c6dd0447..f126ed0c7555 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java @@ -152,6 +152,7 @@ import com.android.systemui.volume.VolumeComponent; import com.android.systemui.wmshell.BubblesManager; import com.android.wm.shell.bubbles.Bubbles; import com.android.wm.shell.legacysplitscreen.LegacySplitScreen; +import com.android.wm.shell.startingsurface.StartingSurface; import org.junit.Before; import org.junit.Test; @@ -273,6 +274,7 @@ public class StatusBarTest extends SysuiTestCase { @Mock private IWallpaperManager mWallpaperManager; @Mock private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController; @Mock private UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController; + @Mock private StartingSurface mStartingSurface; private ShadeController mShadeController; private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock()); private InitController mInitController = new InitController(); @@ -443,7 +445,8 @@ public class StatusBarTest extends SysuiTestCase { mLockscreenTransitionController, mFeatureFlags, mKeyguardUnlockAnimationController, - mUnlockedScreenOffAnimationController); + mUnlockedScreenOffAnimationController, + Optional.of(mStartingSurface)); when(mKeyguardViewMediator.registerStatusBar(any(StatusBar.class), any(ViewGroup.class), any(NotificationPanelViewController.class), any(BiometricUnlockController.class), any(ViewGroup.class), any(KeyguardBypassController.class))) diff --git a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java index 1a24c113a0df..07d3fc20983f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java @@ -466,6 +466,44 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { } @Test + public void catchException_whenPackageNameIsOverlayName() { + mDeviceProvisionedController = mock(DeviceProvisionedController.class); + mThemeOverlayApplier = mock(ThemeOverlayApplier.class); + mWallpaperManager = mock(WallpaperManager.class); + + // Assume we have some wallpaper colors at boot. + when(mWallpaperManager.getWallpaperColors(anyInt())) + .thenReturn(new WallpaperColors(Color.valueOf(Color.GRAY), null, null)); + + Executor executor = MoreExecutors.directExecutor(); + + mThemeOverlayController = new ThemeOverlayController(null /* context */, + mBroadcastDispatcher, mBgHandler, executor, executor, mThemeOverlayApplier, + mSecureSettings, mWallpaperManager, mUserManager, mDeviceProvisionedController, + mUserTracker, mDumpManager, mFeatureFlags, mWakefulnessLifecycle) { + @Nullable + @Override + protected FabricatedOverlay getOverlay(int color, int type) { + FabricatedOverlay overlay = mock(FabricatedOverlay.class); + when(overlay.getIdentifier()) + .thenReturn(new OverlayIdentifier("com.thebest.livewallpaperapp.ever")); + + return overlay; + } + + }; + mThemeOverlayController.start(); + + verify(mWallpaperManager).addOnColorsChangedListener(mColorsListener.capture(), eq(null), + eq(UserHandle.USER_ALL)); + verify(mDeviceProvisionedController).addCallback(mDeviceProvisionedListener.capture()); + + // Colors were applied during controller initialization. + verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any()); + clearInvocations(mThemeOverlayApplier); + } + + @Test public void onWallpaperColorsChanged_defersUntilSetupIsCompleted_ifHasColors() { mDeviceProvisionedController = mock(DeviceProvisionedController.class); mThemeOverlayApplier = mock(ThemeOverlayApplier.class); diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java index 3cea17567173..dd4830e893af 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java @@ -99,6 +99,8 @@ public class VolumeDialogImplTest extends SysuiTestCase { Prefs.putInt(mContext, Prefs.Key.SEEN_RINGER_GUIDANCE_COUNT, VolumePrefs.SHOW_RINGER_TOAST_COUNT + 1); + + Prefs.putBoolean(mContext, Prefs.Key.HAS_SEEN_ODI_CAPTIONS_TOOLTIP, false); } private State createShellState() { diff --git a/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java b/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java index ab3643c2a911..561d079cb984 100644 --- a/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java +++ b/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java @@ -134,6 +134,7 @@ public class CameraExtensionsProxyService extends Service { (!EXTENSIONS_VERSION.startsWith(NON_INIT_VERSION_PREFIX)); private HashMap<String, CameraCharacteristics> mCharacteristicsHashMap = new HashMap<>(); + private HashMap<String, Long> mMetadataVendorIdMap = new HashMap<>(); private static boolean checkForAdvancedAPI() { if (EXTENSIONS_PRESENT && EXTENSIONS_VERSION.startsWith(ADVANCED_VERSION_PREFIX)) { @@ -464,8 +465,16 @@ public class CameraExtensionsProxyService extends Service { String [] cameraIds = manager.getCameraIdListNoLazy(); if (cameraIds != null) { for (String cameraId : cameraIds) { - mCharacteristicsHashMap.put(cameraId, - manager.getCameraCharacteristics(cameraId)); + CameraCharacteristics chars = manager.getCameraCharacteristics(cameraId); + mCharacteristicsHashMap.put(cameraId, chars); + Object thisClass = CameraCharacteristics.Key.class; + Class<CameraCharacteristics.Key<?>> keyClass = + (Class<CameraCharacteristics.Key<?>>)thisClass; + ArrayList<CameraCharacteristics.Key<?>> vendorKeys = + chars.getNativeMetadata().getAllVendorKeys(keyClass); + if ((vendorKeys != null) && !vendorKeys.isEmpty()) { + mMetadataVendorIdMap.put(cameraId, vendorKeys.get(0).getVendorId()); + } } } } catch (CameraAccessException e) { @@ -529,13 +538,16 @@ public class CameraExtensionsProxyService extends Service { return ret; } - private static CameraMetadataNative initializeParcelableMetadata( - List<Pair<CaptureRequest.Key, Object>> paramList) { + private CameraMetadataNative initializeParcelableMetadata( + List<Pair<CaptureRequest.Key, Object>> paramList, String cameraId) { if (paramList == null) { return null; } CameraMetadataNative ret = new CameraMetadataNative(); + if (mMetadataVendorIdMap.containsKey(cameraId)) { + ret.setVendorId(mMetadataVendorIdMap.get(cameraId)); + } for (Pair<CaptureRequest.Key, Object> param : paramList) { ret.set(param.first, param.second); } @@ -543,13 +555,16 @@ public class CameraExtensionsProxyService extends Service { return ret; } - private static CameraMetadataNative initializeParcelableMetadata( - Map<CaptureRequest.Key<?>, Object> paramMap) { + private CameraMetadataNative initializeParcelableMetadata( + Map<CaptureRequest.Key<?>, Object> paramMap, String cameraId) { if (paramMap == null) { return null; } CameraMetadataNative ret = new CameraMetadataNative(); + if (mMetadataVendorIdMap.containsKey(cameraId)) { + ret.setVendorId(mMetadataVendorIdMap.get(cameraId)); + } for (Map.Entry<CaptureRequest.Key<?>, Object> param : paramMap.entrySet()) { ret.set(((CaptureRequest.Key) param.getKey()), param.getValue()); } @@ -557,8 +572,8 @@ public class CameraExtensionsProxyService extends Service { return ret; } - private static android.hardware.camera2.extension.CaptureStageImpl initializeParcelable( - androidx.camera.extensions.impl.CaptureStageImpl captureStage) { + private android.hardware.camera2.extension.CaptureStageImpl initializeParcelable( + androidx.camera.extensions.impl.CaptureStageImpl captureStage, String cameraId) { if (captureStage == null) { return null; } @@ -566,12 +581,13 @@ public class CameraExtensionsProxyService extends Service { android.hardware.camera2.extension.CaptureStageImpl ret = new android.hardware.camera2.extension.CaptureStageImpl(); ret.id = captureStage.getId(); - ret.parameters = initializeParcelableMetadata(captureStage.getParameters()); + ret.parameters = initializeParcelableMetadata(captureStage.getParameters(), cameraId); return ret; } - private Request initializeParcelable(RequestProcessorImpl.Request request, int requestId) { + private Request initializeParcelable(RequestProcessorImpl.Request request, int requestId, + String cameraId) { Request ret = new Request(); ret.targetOutputConfigIds = new ArrayList<>(); for (int id : request.getTargetOutputConfigIds()) { @@ -580,7 +596,7 @@ public class CameraExtensionsProxyService extends Service { ret.targetOutputConfigIds.add(configId); } ret.templateId = request.getTemplateId(); - ret.parameters = initializeParcelableMetadata(request.getParameters()); + ret.parameters = initializeParcelableMetadata(request.getParameters(), cameraId); ret.requestId = requestId; return ret; } @@ -933,9 +949,11 @@ public class CameraExtensionsProxyService extends Service { private class RequestProcessorStub implements RequestProcessorImpl { private final IRequestProcessorImpl mRequestProcessor; + private final String mCameraId; - public RequestProcessorStub(IRequestProcessorImpl requestProcessor) { + public RequestProcessorStub(IRequestProcessorImpl requestProcessor, String cameraId) { mRequestProcessor = requestProcessor; + mCameraId = cameraId; } @Override @@ -964,7 +982,7 @@ public class CameraExtensionsProxyService extends Service { new ArrayList<>(); int requestId = 0; for (Request request : requests) { - captureRequests.add(initializeParcelable(request, requestId)); + captureRequests.add(initializeParcelable(request, requestId, mCameraId)); requestId++; } @@ -982,7 +1000,8 @@ public class CameraExtensionsProxyService extends Service { try { ArrayList<Request> requests = new ArrayList<>(); requests.add(request); - return mRequestProcessor.setRepeating(initializeParcelable(request, 0), + return mRequestProcessor.setRepeating( + initializeParcelable(request, 0, mCameraId), new RequestCallbackStub(requests, callback)); } catch (RemoteException e) { Log.e(TAG, "Failed to submit repeating request due to remote exception!"); @@ -1012,6 +1031,7 @@ public class CameraExtensionsProxyService extends Service { private class SessionProcessorImplStub extends ISessionProcessorImpl.Stub { private final SessionProcessorImpl mSessionProcessor; + private String mCameraId = null; public SessionProcessorImplStub(SessionProcessorImpl sessionProcessor) { mSessionProcessor = sessionProcessor; @@ -1074,7 +1094,8 @@ public class CameraExtensionsProxyService extends Service { } ret.sessionTemplateId = sessionConfig.getSessionTemplateId(); ret.sessionParameter = initializeParcelableMetadata( - sessionConfig.getSessionParameters()); + sessionConfig.getSessionParameters(), cameraId); + mCameraId = cameraId; return ret; } @@ -1086,7 +1107,8 @@ public class CameraExtensionsProxyService extends Service { @Override public void onCaptureSessionStart(IRequestProcessorImpl requestProcessor) { - mSessionProcessor.onCaptureSessionStart(new RequestProcessorStub(requestProcessor)); + mSessionProcessor.onCaptureSessionStart( + new RequestProcessorStub(requestProcessor, mCameraId)); } @Override @@ -1143,6 +1165,7 @@ public class CameraExtensionsProxyService extends Service { private class PreviewExtenderImplStub extends IPreviewExtenderImpl.Stub { private final PreviewExtenderImpl mPreviewExtender; + private String mCameraId = null; public PreviewExtenderImplStub(PreviewExtenderImpl previewExtender) { mPreviewExtender = previewExtender; @@ -1150,6 +1173,7 @@ public class CameraExtensionsProxyService extends Service { @Override public void onInit(String cameraId, CameraMetadataNative cameraCharacteristics) { + mCameraId = cameraId; mPreviewExtender.onInit(cameraId, new CameraCharacteristics(cameraCharacteristics), CameraExtensionsProxyService.this); } @@ -1161,17 +1185,17 @@ public class CameraExtensionsProxyService extends Service { @Override public CaptureStageImpl onPresetSession() { - return initializeParcelable(mPreviewExtender.onPresetSession()); + return initializeParcelable(mPreviewExtender.onPresetSession(), mCameraId); } @Override public CaptureStageImpl onEnableSession() { - return initializeParcelable(mPreviewExtender.onEnableSession()); + return initializeParcelable(mPreviewExtender.onEnableSession(), mCameraId); } @Override public CaptureStageImpl onDisableSession() { - return initializeParcelable(mPreviewExtender.onDisableSession()); + return initializeParcelable(mPreviewExtender.onDisableSession(), mCameraId); } @Override @@ -1187,7 +1211,7 @@ public class CameraExtensionsProxyService extends Service { @Override public CaptureStageImpl getCaptureStage() { - return initializeParcelable(mPreviewExtender.getCaptureStage()); + return initializeParcelable(mPreviewExtender.getCaptureStage(), mCameraId); } @Override @@ -1230,7 +1254,7 @@ public class CameraExtensionsProxyService extends Service { } if (processor != null) { - return new RequestUpdateProcessorImplStub(processor); + return new RequestUpdateProcessorImplStub(processor, mCameraId); } return null; @@ -1251,6 +1275,7 @@ public class CameraExtensionsProxyService extends Service { private class ImageCaptureExtenderImplStub extends IImageCaptureExtenderImpl.Stub { private final ImageCaptureExtenderImpl mImageExtender; + private String mCameraId = null; public ImageCaptureExtenderImplStub(ImageCaptureExtenderImpl imageExtender) { mImageExtender = imageExtender; @@ -1260,6 +1285,7 @@ public class CameraExtensionsProxyService extends Service { public void onInit(String cameraId, CameraMetadataNative cameraCharacteristics) { mImageExtender.onInit(cameraId, new CameraCharacteristics(cameraCharacteristics), CameraExtensionsProxyService.this); + mCameraId = cameraId; } @Override @@ -1269,17 +1295,17 @@ public class CameraExtensionsProxyService extends Service { @Override public CaptureStageImpl onPresetSession() { - return initializeParcelable(mImageExtender.onPresetSession()); + return initializeParcelable(mImageExtender.onPresetSession(), mCameraId); } @Override public CaptureStageImpl onEnableSession() { - return initializeParcelable(mImageExtender.onEnableSession()); + return initializeParcelable(mImageExtender.onEnableSession(), mCameraId); } @Override public CaptureStageImpl onDisableSession() { - return initializeParcelable(mImageExtender.onDisableSession()); + return initializeParcelable(mImageExtender.onDisableSession(), mCameraId); } @Override @@ -1312,7 +1338,7 @@ public class CameraExtensionsProxyService extends Service { ArrayList<android.hardware.camera2.extension.CaptureStageImpl> ret = new ArrayList<>(); for (androidx.camera.extensions.impl.CaptureStageImpl stage : captureStages) { - ret.add(initializeParcelable(stage)); + ret.add(initializeParcelable(stage, mCameraId)); } return ret; @@ -1428,9 +1454,12 @@ public class CameraExtensionsProxyService extends Service { private class RequestUpdateProcessorImplStub extends IRequestUpdateProcessorImpl.Stub { private final RequestUpdateProcessorImpl mProcessor; + private final String mCameraId; - public RequestUpdateProcessorImplStub(RequestUpdateProcessorImpl processor) { + public RequestUpdateProcessorImplStub(RequestUpdateProcessorImpl processor, + String cameraId) { mProcessor = processor; + mCameraId = cameraId; } @Override @@ -1451,7 +1480,7 @@ public class CameraExtensionsProxyService extends Service { @Override public CaptureStageImpl process(CameraMetadataNative result, int sequenceId) { return initializeParcelable( - mProcessor.process(new TotalCaptureResult(result, sequenceId))); + mProcessor.process(new TotalCaptureResult(result, sequenceId)), mCameraId); } } diff --git a/proto/src/system_messages.proto b/proto/src/system_messages.proto index a48f76ea1ca3..3047c9042848 100644 --- a/proto/src/system_messages.proto +++ b/proto/src/system_messages.proto @@ -268,6 +268,14 @@ message SystemMessage { // Package: android NOTE_NAS_UPGRADE = 64; + // Notify the user to unblock the microphone global toggle + // Package: android + NOTE_UNBLOCK_MIC_TOGGLE = 65; + + // Notify the user to unblock the camera global toggle + // Package: android + NOTE_UNBLOCK_CAM_TOGGLE = 66; + // ADD_NEW_IDS_ABOVE_THIS_LINE // Legacy IDs with arbitrary values appear below // Legacy IDs existed as stable non-conflicting constants prior to the O release diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java index 9ff1b10c09ed..b7feb6306c99 100644 --- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java +++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java @@ -865,7 +865,7 @@ public class CompanionDeviceManagerService extends SystemService implements Bind Set<String> sameOemPackageCerts = new HashSet<>(); // Assume OEM may enter same package name in the parallel string array with - // multiple ADK certs corresponding to it + // multiple APK certs corresponding to it for (int i = 0; i < oemPackages.length; i++) { if (oemPackages[i].equals(packageName)) { sameOemPackageCerts.add(sameOemCerts[i].replaceAll(":", "")); diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java index f7ddd2922b25..95186ee444e4 100644 --- a/services/core/java/android/content/pm/PackageManagerInternal.java +++ b/services/core/java/android/content/pm/PackageManagerInternal.java @@ -566,6 +566,12 @@ public abstract class PackageManagerInternal implements PackageSettingsSnapshotP public abstract ProviderInfo resolveContentProvider(String name, int flags, int userId); /** + * Resolves a content provider intent. + */ + public abstract ProviderInfo resolveContentProvider(String name, int flags, int userId, + int callingUid); + + /** * Track the creator of a new isolated uid. * @param isolatedUid The newly created isolated uid. * @param ownerUid The uid of the app that created the isolated process. diff --git a/services/core/java/com/android/server/GestureLauncherService.java b/services/core/java/com/android/server/GestureLauncherService.java index 50b27a0f3b3d..d04698cb5aeb 100644 --- a/services/core/java/com/android/server/GestureLauncherService.java +++ b/services/core/java/com/android/server/GestureLauncherService.java @@ -519,15 +519,6 @@ public class GestureLauncherService extends SystemService { // user has completed setup. return intercept && isUserSetupComplete(); } - - public boolean isCameraDoubleTapPowerEnabled() { - return mCameraDoubleTapPowerEnabled; - } - - public boolean isEmergencyGestureEnabled() { - return mEmergencyGestureEnabled; - } - /** * @return true if camera was launched, false otherwise. */ diff --git a/services/core/java/com/android/server/SensorPrivacyService.java b/services/core/java/com/android/server/SensorPrivacyService.java index 51ad23c103dc..ac43fbd4f976 100644 --- a/services/core/java/com/android/server/SensorPrivacyService.java +++ b/services/core/java/com/android/server/SensorPrivacyService.java @@ -36,9 +36,26 @@ import static android.hardware.SensorPrivacyManager.EXTRA_ALL_SENSORS; import static android.hardware.SensorPrivacyManager.EXTRA_SENSOR; import static android.hardware.SensorPrivacyManager.Sensors.CAMERA; import static android.hardware.SensorPrivacyManager.Sensors.MICROPHONE; +import static android.hardware.SensorPrivacyManager.Sources.DIALOG; +import static android.hardware.SensorPrivacyManager.Sources.OTHER; +import static android.hardware.SensorPrivacyManager.Sources.QS_TILE; +import static android.hardware.SensorPrivacyManager.Sources.SETTINGS; +import static android.hardware.SensorPrivacyManager.Sources.SHELL; import static android.os.UserHandle.USER_SYSTEM; import static android.service.SensorPrivacyIndividualEnabledSensorProto.UNKNOWN; +import static com.android.internal.util.FrameworkStatsLog.PRIVACY_SENSOR_TOGGLE_INTERACTION; +import static com.android.internal.util.FrameworkStatsLog.PRIVACY_SENSOR_TOGGLE_INTERACTION__ACTION__TOGGLE_OFF; +import static com.android.internal.util.FrameworkStatsLog.PRIVACY_SENSOR_TOGGLE_INTERACTION__ACTION__TOGGLE_ON; +import static com.android.internal.util.FrameworkStatsLog.PRIVACY_SENSOR_TOGGLE_INTERACTION__SENSOR__CAMERA; +import static com.android.internal.util.FrameworkStatsLog.PRIVACY_SENSOR_TOGGLE_INTERACTION__SENSOR__MICROPHONE; +import static com.android.internal.util.FrameworkStatsLog.PRIVACY_SENSOR_TOGGLE_INTERACTION__SENSOR__SENSOR_UNKNOWN; +import static com.android.internal.util.FrameworkStatsLog.PRIVACY_SENSOR_TOGGLE_INTERACTION__SOURCE__DIALOG; +import static com.android.internal.util.FrameworkStatsLog.PRIVACY_SENSOR_TOGGLE_INTERACTION__SOURCE__QS_TILE; +import static com.android.internal.util.FrameworkStatsLog.PRIVACY_SENSOR_TOGGLE_INTERACTION__SOURCE__SETTINGS; +import static com.android.internal.util.FrameworkStatsLog.PRIVACY_SENSOR_TOGGLE_INTERACTION__SOURCE__SOURCE_UNKNOWN; +import static com.android.internal.util.FrameworkStatsLog.write; + import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; @@ -77,6 +94,7 @@ import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ShellCallback; import android.os.ShellCommand; +import android.os.SystemClock; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; @@ -104,6 +122,7 @@ import android.util.proto.ProtoOutputStream; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; +import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; import com.android.internal.os.BackgroundThread; import com.android.internal.util.DumpUtils; import com.android.internal.util.FunctionalUtils; @@ -130,6 +149,8 @@ import java.util.Objects; public final class SensorPrivacyService extends SystemService { private static final String TAG = SensorPrivacyService.class.getSimpleName(); + private static final boolean DEBUG = false; + private static final boolean DEBUG_LOGGING = false; /** Version number indicating compatibility parsing the persisted file */ private static final int CURRENT_PERSISTENCE_VERSION = 1; @@ -145,6 +166,7 @@ public final class SensorPrivacyService extends SystemService { private static final String XML_ATTRIBUTE_PERSISTENCE_VERSION = "persistence-version"; private static final String XML_ATTRIBUTE_VERSION = "version"; private static final String XML_ATTRIBUTE_ENABLED = "enabled"; + private static final String XML_ATTRIBUTE_LAST_CHANGE = "last-change"; private static final String XML_ATTRIBUTE_SENSOR = "sensor"; private static final String SENSOR_PRIVACY_CHANNEL_ID = Context.SENSOR_PRIVACY_SERVICE; @@ -231,7 +253,7 @@ public final class SensorPrivacyService extends SystemService { @GuardedBy("mLock") private SparseBooleanArray mEnabled = new SparseBooleanArray(); @GuardedBy("mLock") - private SparseArray<SparseBooleanArray> mIndividualEnabled = new SparseArray<>(); + private SparseArray<SparseArray<SensorState>> mIndividualEnabled = new SparseArray<>(); /** * Packages for which not to show sensor use reminders. @@ -239,12 +261,40 @@ public final class SensorPrivacyService extends SystemService { * <Package, User> -> list of suppressor tokens */ @GuardedBy("mLock") - private ArrayMap<Pair<String, UserHandle>, ArrayList<IBinder>> mSuppressReminders = + private ArrayMap<Pair<Integer, UserHandle>, ArrayList<IBinder>> mSuppressReminders = new ArrayMap<>(); private final ArrayMap<SensorUseReminderDialogInfo, ArraySet<Integer>> mQueuedSensorUseReminderDialogs = new ArrayMap<>(); + private class SensorState { + private boolean mEnabled; + private long mLastChange; + + SensorState(boolean enabled) { + mEnabled = enabled; + mLastChange = getCurrentTimeMillis(); + } + + SensorState(boolean enabled, long lastChange) { + mEnabled = enabled; + if (lastChange < 0) { + mLastChange = getCurrentTimeMillis(); + } else { + mLastChange = lastChange; + } + } + + boolean setEnabled(boolean enabled) { + if (mEnabled != enabled) { + mEnabled = enabled; + mLastChange = getCurrentTimeMillis(); + return true; + } + return false; + } + } + private class SensorUseReminderDialogInfo { private int mTaskId; private UserHandle mUser; @@ -288,12 +338,14 @@ public final class SensorPrivacyService extends SystemService { mAppOpsManager.startWatchingNoted(micAndCameraOps, this); mAppOpsManager.startWatchingStarted(micAndCameraOps, this); + + mContext.registerReceiver(new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { setIndividualSensorPrivacy( ((UserHandle) intent.getParcelableExtra( - Intent.EXTRA_USER)).getIdentifier(), + Intent.EXTRA_USER)).getIdentifier(), OTHER, intent.getIntExtra(EXTRA_SENSOR, UNKNOWN), false); } }, new IntentFilter(ACTION_DISABLE_INDIVIDUAL_SENSOR_PRIVACY), @@ -307,11 +359,11 @@ public final class SensorPrivacyService extends SystemService { // Reset sensor privacy when restriction is added if (!prevRestrictions.getBoolean(UserManager.DISALLOW_CAMERA_TOGGLE) && newRestrictions.getBoolean(UserManager.DISALLOW_CAMERA_TOGGLE)) { - setIndividualSensorPrivacyUnchecked(userId, CAMERA, false); + setIndividualSensorPrivacyUnchecked(userId, OTHER, CAMERA, false); } if (!prevRestrictions.getBoolean(UserManager.DISALLOW_MICROPHONE_TOGGLE) && newRestrictions.getBoolean(UserManager.DISALLOW_MICROPHONE_TOGGLE)) { - setIndividualSensorPrivacyUnchecked(userId, MICROPHONE, false); + setIndividualSensorPrivacyUnchecked(userId, OTHER, MICROPHONE, false); } } @@ -372,7 +424,7 @@ public final class SensorPrivacyService extends SystemService { } synchronized (mLock) { - if (mSuppressReminders.containsKey(new Pair<>(packageName, user))) { + if (mSuppressReminders.containsKey(new Pair<>(sensor, user))) { Log.d(TAG, "Suppressed sensor privacy reminder for " + packageName + "/" + user); return; @@ -399,14 +451,22 @@ public final class SensorPrivacyService extends SystemService { for (int taskNum = 0; taskNum < numTasks; taskNum++) { RunningTaskInfo task = tasks.get(taskNum); - if (task.isVisible && task.topActivity.getPackageName().equals(packageName)) { - if (task.isFocused) { - // There is the one focused activity - enqueueSensorUseReminderDialogAsync(task.taskId, user, packageName, sensor); - return; - } + if (task.isVisible) { + if (task.topActivity.getPackageName().equals(packageName)) { + if (task.isFocused) { + // There is the one focused activity + enqueueSensorUseReminderDialogAsync(task.taskId, user, packageName, + sensor); + return; + } - tasksOfPackageUsingSensor.add(task); + tasksOfPackageUsingSensor.add(task); + } else if (task.topActivity.flattenToString().equals(mContext.getResources() + .getString(R.string.config_sensorUseStartedActivity)) + && task.isFocused) { + enqueueSensorUseReminderDialogAsync(task.taskId, user, packageName, + sensor); + } } } @@ -499,8 +559,15 @@ public final class SensorPrivacyService extends SystemService { SensorUseReminderDialogInfo info = new SensorUseReminderDialogInfo(taskId, user, packageName); if (!mQueuedSensorUseReminderDialogs.containsKey(info)) { - ArraySet<Integer> sensors = new ArraySet<Integer>(); - sensors.add(sensor); + ArraySet<Integer> sensors = new ArraySet<>(); + if (sensor == MICROPHONE && mSuppressReminders.containsKey(new Pair<>(CAMERA, user)) + || sensor == CAMERA && mSuppressReminders + .containsKey(new Pair<>(MICROPHONE, user))) { + sensors.add(MICROPHONE); + sensors.add(CAMERA); + } else { + sensors.add(sensor); + } mQueuedSensorUseReminderDialogs.put(info, sensors); mHandler.sendMessageDelayed( PooledLambda.obtainMessage(this::showSensorUserReminderDialog, info), @@ -557,6 +624,7 @@ public final class SensorPrivacyService extends SystemService { @NonNull String packageName, int sensor) { int iconRes; int messageRes; + int notificationId; CharSequence packageLabel; try { @@ -571,9 +639,11 @@ public final class SensorPrivacyService extends SystemService { if (sensor == MICROPHONE) { iconRes = R.drawable.ic_mic_blocked; messageRes = R.string.sensor_privacy_start_use_mic_notification_content_title; + notificationId = SystemMessage.NOTE_UNBLOCK_MIC_TOGGLE; } else { iconRes = R.drawable.ic_camera_blocked; messageRes = R.string.sensor_privacy_start_use_camera_notification_content_title; + notificationId = SystemMessage.NOTE_UNBLOCK_CAM_TOGGLE; } NotificationManager notificationManager = @@ -590,7 +660,7 @@ public final class SensorPrivacyService extends SystemService { notificationManager.createNotificationChannel(channel); Icon icon = Icon.createWithResource(getUiContext().getResources(), iconRes); - notificationManager.notify(sensor, + notificationManager.notify(notificationId, new Notification.Builder(mContext, SENSOR_PRIVACY_CHANNEL_ID) .setContentTitle(getUiContext().getString(messageRes)) .setContentText(Html.fromHtml(getUiContext().getString( @@ -645,22 +715,40 @@ public final class SensorPrivacyService extends SystemService { } @Override - public void setIndividualSensorPrivacy(@UserIdInt int userId, int sensor, boolean enable) { + public void setIndividualSensorPrivacy(@UserIdInt int userId, + @SensorPrivacyManager.Sources.Source int source, int sensor, boolean enable) { enforceManageSensorPrivacyPermission(); if (!canChangeIndividualSensorPrivacy(userId, sensor)) { return; } - setIndividualSensorPrivacyUnchecked(userId, sensor, enable); + setIndividualSensorPrivacyUnchecked(userId, source, sensor, enable); } - private void setIndividualSensorPrivacyUnchecked(int userId, int sensor, boolean enable) { + private void setIndividualSensorPrivacyUnchecked(int userId, int source, int sensor, + boolean enable) { synchronized (mLock) { - SparseBooleanArray userIndividualEnabled = mIndividualEnabled.get(userId, - new SparseBooleanArray()); - userIndividualEnabled.put(sensor, enable); + SparseArray<SensorState> userIndividualEnabled = mIndividualEnabled.get(userId, + new SparseArray<>()); + SensorState sensorState = userIndividualEnabled.get(sensor); + long lastChange; + if (sensorState != null) { + lastChange = sensorState.mLastChange; + if (!sensorState.setEnabled(enable)) { + // State not changing + return; + } + } else { + sensorState = new SensorState(enable); + lastChange = sensorState.mLastChange; + userIndividualEnabled.put(sensor, sensorState); + } mIndividualEnabled.put(userId, userIndividualEnabled); + if (userId == mUserManagerInternal.getProfileParentId(userId)) { + logSensorPrivacyToggle(source, sensor, sensorState.mEnabled, lastChange); + } + if (!enable) { long token = Binder.clearCallingIdentity(); try { @@ -704,14 +792,61 @@ public final class SensorPrivacyService extends SystemService { return true; } + private void logSensorPrivacyToggle(int source, int sensor, boolean enabled, + long lastChange) { + long logMins = Math.max(0, (getCurrentTimeMillis() - lastChange) / (1000 * 60)); + + int logAction = -1; + if (enabled) { + logAction = PRIVACY_SENSOR_TOGGLE_INTERACTION__ACTION__TOGGLE_OFF; + } else { + logAction = PRIVACY_SENSOR_TOGGLE_INTERACTION__ACTION__TOGGLE_ON; + } + + int logSensor = -1; + switch(sensor) { + case CAMERA: + logSensor = PRIVACY_SENSOR_TOGGLE_INTERACTION__SENSOR__CAMERA; + break; + case MICROPHONE: + logSensor = PRIVACY_SENSOR_TOGGLE_INTERACTION__SENSOR__MICROPHONE; + break; + default: + logSensor = PRIVACY_SENSOR_TOGGLE_INTERACTION__SENSOR__SENSOR_UNKNOWN; + } + + int logSource = -1; + switch(source) { + case QS_TILE : + logSource = PRIVACY_SENSOR_TOGGLE_INTERACTION__SOURCE__QS_TILE; + break; + case DIALOG : + logSource = PRIVACY_SENSOR_TOGGLE_INTERACTION__SOURCE__DIALOG; + break; + case SETTINGS: + logSource = PRIVACY_SENSOR_TOGGLE_INTERACTION__SOURCE__SETTINGS; + break; + default: + logSource = PRIVACY_SENSOR_TOGGLE_INTERACTION__SOURCE__SOURCE_UNKNOWN; + } + + if (DEBUG || DEBUG_LOGGING) { + Log.d(TAG, "Logging sensor toggle interaction:" + " logSensor=" + logSensor + + " logAction=" + logAction + " logSource=" + logSource + " logMins=" + + logMins); + } + write(PRIVACY_SENSOR_TOGGLE_INTERACTION, logSensor, logAction, logSource, logMins); + + } + @Override - public void setIndividualSensorPrivacyForProfileGroup(@UserIdInt int userId, int sensor, - boolean enable) { + public void setIndividualSensorPrivacyForProfileGroup(@UserIdInt int userId, + @SensorPrivacyManager.Sources.Source int source, int sensor, boolean enable) { enforceManageSensorPrivacyPermission(); int parentId = mUserManagerInternal.getProfileParentId(userId); forAllUsers(userId2 -> { if (parentId == mUserManagerInternal.getProfileParentId(userId2)) { - setIndividualSensorPrivacy(userId2, sensor, enable); + setIndividualSensorPrivacy(userId2, source, sensor, enable); } }); } @@ -762,11 +897,15 @@ public final class SensorPrivacyService extends SystemService { public boolean isIndividualSensorPrivacyEnabled(@UserIdInt int userId, int sensor) { enforceObserveSensorPrivacyPermission(); synchronized (mLock) { - SparseBooleanArray states = mIndividualEnabled.get(userId); + SparseArray<SensorState> states = mIndividualEnabled.get(userId); if (states == null) { return false; } - return states.get(sensor, false); + SensorState state = states.get(sensor); + if (state == null) { + return false; + } + return state.mEnabled; } } @@ -791,7 +930,7 @@ public final class SensorPrivacyService extends SystemService { // these should never be changed even with refactorings. if (persistenceVersion == 0) { boolean enabled = parser.getAttributeBoolean(null, "enabled", false); - SparseBooleanArray individualEnabled = new SparseBooleanArray(); + SparseArray<SensorState> individualEnabled = new SparseArray<>(); version = 0; XmlUtils.nextElement(parser); @@ -801,7 +940,7 @@ public final class SensorPrivacyService extends SystemService { int sensor = XmlUtils.readIntAttribute(parser, "sensor"); boolean indEnabled = XmlUtils.readBooleanAttribute(parser, "enabled"); - individualEnabled.put(sensor, indEnabled); + individualEnabled.put(sensor, new SensorState(indEnabled)); XmlUtils.skipCurrentTag(parser); } else { XmlUtils.nextElement(parser); @@ -811,7 +950,8 @@ public final class SensorPrivacyService extends SystemService { map.put(VER0_INDIVIDUAL_ENABLED, individualEnabled); } else if (persistenceVersion == CURRENT_PERSISTENCE_VERSION) { SparseBooleanArray enabled = new SparseBooleanArray(); - SparseArray<SparseBooleanArray> individualEnabled = new SparseArray<>(); + SparseArray<SparseArray<SensorState>> individualEnabled = + new SparseArray<>(); version = parser.getAttributeInt(null, XML_ATTRIBUTE_VERSION, 1); @@ -847,10 +987,13 @@ public final class SensorPrivacyService extends SystemService { int sensor = parser.getAttributeInt(null, XML_ATTRIBUTE_SENSOR); boolean isEnabled = parser.getAttributeBoolean(null, XML_ATTRIBUTE_ENABLED); - SparseBooleanArray userIndividualEnabled = individualEnabled.get( - currentUserId, new SparseBooleanArray()); + long lastChange = parser + .getAttributeLong(null, XML_ATTRIBUTE_LAST_CHANGE, -1); + SparseArray<SensorState> userIndividualEnabled = + individualEnabled.get(currentUserId, new SparseArray<>()); - userIndividualEnabled.put(sensor, isEnabled); + userIndividualEnabled + .put(sensor, new SensorState(isEnabled, lastChange)); individualEnabled.put(currentUserId, userIndividualEnabled); } } @@ -883,7 +1026,7 @@ public final class SensorPrivacyService extends SystemService { mEnabled = new SparseBooleanArray(); mIndividualEnabled = new SparseArray<>(); forAllUsers(userId -> mEnabled.put(userId, false)); - forAllUsers(userId -> mIndividualEnabled.put(userId, new SparseBooleanArray())); + forAllUsers(userId -> mIndividualEnabled.put(userId, new SparseArray<>())); return true; } boolean upgraded = false; @@ -920,7 +1063,7 @@ public final class SensorPrivacyService extends SystemService { if (version == CURRENT_VERSION) { mEnabled = (SparseBooleanArray) map.get(VER1_ENABLED); mIndividualEnabled = - (SparseArray<SparseBooleanArray>) map.get(VER1_INDIVIDUAL_ENABLED); + (SparseArray<SparseArray<SensorState>>) map.get(VER1_INDIVIDUAL_ENABLED); } return upgraded; } @@ -950,15 +1093,18 @@ public final class SensorPrivacyService extends SystemService { serializer.attributeBoolean( null, XML_ATTRIBUTE_ENABLED, isSensorPrivacyEnabled(userId)); - SparseBooleanArray individualEnabled = - mIndividualEnabled.get(userId, new SparseBooleanArray()); + SparseArray<SensorState> individualEnabled = + mIndividualEnabled.get(userId, new SparseArray<>()); int numIndividual = individualEnabled.size(); for (int i = 0; i < numIndividual; i++) { serializer.startTag(null, XML_TAG_INDIVIDUAL_SENSOR_PRIVACY); int sensor = individualEnabled.keyAt(i); - boolean enabled = individualEnabled.valueAt(i); + SensorState sensorState = individualEnabled.valueAt(i); + boolean enabled = sensorState.mEnabled; + long lastChange = sensorState.mLastChange; serializer.attributeInt(null, XML_ATTRIBUTE_SENSOR, sensor); serializer.attributeBoolean(null, XML_ATTRIBUTE_ENABLED, enabled); + serializer.attributeLong(null, XML_ATTRIBUTE_LAST_CHANGE, lastChange); serializer.endTag(null, XML_TAG_INDIVIDUAL_SENSOR_PRIVACY); } serializer.endTag(null, XML_TAG_USER); @@ -1034,13 +1180,12 @@ public final class SensorPrivacyService extends SystemService { } @Override - public void suppressIndividualSensorPrivacyReminders(int userId, String packageName, + public void suppressIndividualSensorPrivacyReminders(int userId, int sensor, IBinder token, boolean suppress) { enforceManageSensorPrivacyPermission(); - Objects.requireNonNull(packageName); Objects.requireNonNull(token); - Pair<String, UserHandle> key = new Pair<>(packageName, UserHandle.of(userId)); + Pair<Integer, UserHandle> key = new Pair<>(sensor, UserHandle.of(userId)); synchronized (mLock) { if (suppress) { @@ -1070,7 +1215,7 @@ public final class SensorPrivacyService extends SystemService { * @param key Key the token is in * @param token The token to remove */ - private void removeSuppressPackageReminderToken(@NonNull Pair<String, UserHandle> key, + private void removeSuppressPackageReminderToken(@NonNull Pair<Integer, UserHandle> key, @NonNull IBinder token) { synchronized (mLock) { ArrayList<IBinder> suppressPackageReminderTokens = @@ -1102,7 +1247,7 @@ public final class SensorPrivacyService extends SystemService { @Override public void binderDied(@NonNull IBinder token) { synchronized (mLock) { - for (Pair<String, UserHandle> key : mSuppressReminders.keySet()) { + for (Pair<Integer, UserHandle> key : mSuppressReminders.keySet()) { removeSuppressPackageReminderToken(key, token); } } @@ -1163,7 +1308,7 @@ public final class SensorPrivacyService extends SystemService { dumpStream.write("is_enabled", SensorPrivacyUserProto.IS_ENABLED, mEnabled.get(userId, false)); - SparseBooleanArray individualEnabled = mIndividualEnabled.get(userId); + SparseArray<SensorState> individualEnabled = mIndividualEnabled.get(userId); if (individualEnabled != null) { int numIndividualEnabled = individualEnabled.size(); for (int i = 0; i < numIndividualEnabled; i++) { @@ -1175,7 +1320,8 @@ public final class SensorPrivacyService extends SystemService { individualEnabled.keyAt(i)); dumpStream.write("is_enabled", SensorPrivacyIndividualEnabledSensorProto.IS_ENABLED, - individualEnabled.valueAt(i)); + individualEnabled.valueAt(i).mEnabled); + // TODO dump last change dumpStream.end(individualToken); } @@ -1232,7 +1378,7 @@ public final class SensorPrivacyService extends SystemService { return -1; } - setIndividualSensorPrivacy(userId, sensor, true); + setIndividualSensorPrivacy(userId, SHELL, sensor, true); } break; case "disable" : { @@ -1242,7 +1388,7 @@ public final class SensorPrivacyService extends SystemService { return -1; } - setIndividualSensorPrivacy(userId, sensor, false); + setIndividualSensorPrivacy(userId, SHELL, sensor, false); } break; case "reset": { @@ -1255,7 +1401,7 @@ public final class SensorPrivacyService extends SystemService { enforceManageSensorPrivacyPermission(); synchronized (mLock) { - SparseBooleanArray individualEnabled = + SparseArray<SensorState> individualEnabled = mIndividualEnabled.get(userId); if (individualEnabled != null) { individualEnabled.delete(sensor); @@ -1429,7 +1575,7 @@ public final class SensorPrivacyService extends SystemService { listeners.finishBroadcast(); } - public void removeSuppressPackageReminderToken(Pair<String, UserHandle> key, + public void removeSuppressPackageReminderToken(Pair<Integer, UserHandle> key, IBinder token) { sendMessage(PooledLambda.obtainMessage( SensorPrivacyServiceImpl::removeSuppressPackageReminderToken, @@ -1616,7 +1762,7 @@ public final class SensorPrivacyService extends SystemService { if (mSensorPrivacyServiceImpl .isIndividualSensorPrivacyEnabled(getCurrentUser(), MICROPHONE)) { mSensorPrivacyServiceImpl.setIndividualSensorPrivacyUnchecked( - getCurrentUser(), MICROPHONE, false); + getCurrentUser(), OTHER, MICROPHONE, false); mMicUnmutedForEmergencyCall = true; } else { mMicUnmutedForEmergencyCall = false; @@ -1631,11 +1777,19 @@ public final class SensorPrivacyService extends SystemService { mIsInEmergencyCall = false; if (mMicUnmutedForEmergencyCall) { mSensorPrivacyServiceImpl.setIndividualSensorPrivacyUnchecked( - getCurrentUser(), MICROPHONE, true); + getCurrentUser(), OTHER, MICROPHONE, true); mMicUnmutedForEmergencyCall = false; } } } } } + + private static long getCurrentTimeMillis() { + try { + return SystemClock.currentNetworkTimeMillis(); + } catch (Exception e) { + return System.currentTimeMillis(); + } + } } diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 875ef377f442..b5ead200cea5 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -32,11 +32,11 @@ import static android.os.PowerExemptionManager.REASON_ALLOWLISTED_PACKAGE; import static android.os.PowerExemptionManager.REASON_BACKGROUND_ACTIVITY_PERMISSION; import static android.os.PowerExemptionManager.REASON_BACKGROUND_FGS_PERMISSION; import static android.os.PowerExemptionManager.REASON_COMPANION_DEVICE_MANAGER; +import static android.os.PowerExemptionManager.REASON_CURRENT_INPUT_METHOD; import static android.os.PowerExemptionManager.REASON_DENIED; import static android.os.PowerExemptionManager.REASON_DEVICE_DEMO_MODE; import static android.os.PowerExemptionManager.REASON_DEVICE_OWNER; import static android.os.PowerExemptionManager.REASON_FGS_BINDING; -import static android.os.PowerExemptionManager.REASON_CURRENT_INPUT_METHOD; import static android.os.PowerExemptionManager.REASON_INSTR_BACKGROUND_ACTIVITY_PERMISSION; import static android.os.PowerExemptionManager.REASON_INSTR_BACKGROUND_FGS_PERMISSION; import static android.os.PowerExemptionManager.REASON_OPT_OUT_REQUESTED; @@ -1997,11 +1997,17 @@ public final class ActiveServices { } ServiceNotificationPolicy applyForegroundServiceNotificationLocked(Notification notification, - final int id, final String pkg, final int userId) { + final String tag, final int id, final String pkg, final int userId) { + // By nature of the FGS API, all FGS notifications have a null tag + if (tag != null) { + return ServiceNotificationPolicy.NOT_FOREGROUND_SERVICE; + } + if (DEBUG_FOREGROUND_SERVICE) { Slog.d(TAG_SERVICE, "Evaluating FGS policy for id=" + id + " pkg=" + pkg + " not=" + notification); } + // Is there an FGS using this notification? final ServiceMap smap = mServiceMap.get(userId); if (smap == null) { @@ -2483,7 +2489,7 @@ public final class ActiveServices { } private void cancelForegroundNotificationLocked(ServiceRecord r) { - if (r.foregroundId != 0) { + if (r.foregroundNoti != null) { // First check to see if this app has any other active foreground services // with the same notification ID. If so, we shouldn't actually cancel it, // because that would wipe away the notification that still needs to be shown @@ -2492,9 +2498,16 @@ public final class ActiveServices { if (sm != null) { for (int i = sm.mServicesByInstanceName.size() - 1; i >= 0; i--) { ServiceRecord other = sm.mServicesByInstanceName.valueAt(i); - if (other != r && other.foregroundId == r.foregroundId + if (other != r + && other.isForeground + && other.foregroundId == r.foregroundId && other.packageName.equals(r.packageName)) { - // Found one! Abort the cancel. + if (DEBUG_FOREGROUND_SERVICE) { + Slog.i(TAG_SERVICE, "FGS notification for " + r + + " shared by " + other + + " (isForeground=" + other.isForeground + ")" + + " - NOT cancelling"); + } return; } } @@ -4282,6 +4295,10 @@ public final class ActiveServices { } private void dropFgsNotificationStateLocked(ServiceRecord r) { + if (r.foregroundNoti == null) { + return; + } + // If this is the only FGS using this notification, clear its FGS flag boolean shared = false; final ServiceMap smap = mServiceMap.get(r.userId); diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java index 530f918833ad..ac0a1985ac89 100644 --- a/services/core/java/com/android/server/am/ActivityManagerConstants.java +++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java @@ -489,7 +489,7 @@ final class ActivityManagerConstants extends ContentObserver { volatile long mFgsStartForegroundTimeoutMs = DEFAULT_FGS_START_FOREGROUND_TIMEOUT_MS; /** - * Sample rate for the FGS westworld atom. + * Sample rate for the FGS atom. * * If the value is 0.1, 10% of the installed packages would be sampled. */ @@ -506,6 +506,7 @@ final class ActivityManagerConstants extends ContentObserver { private final KeyValueListParser mParser = new KeyValueListParser(','); private int mOverrideMaxCachedProcesses = -1; + private final int mCustomizedMaxCachedProcesses; // The maximum number of cached processes we will keep around before killing them. // NOTE: this constant is *only* a control to not let us go too crazy with @@ -515,11 +516,12 @@ final class ActivityManagerConstants extends ContentObserver { // kill them. Also note that this limit only applies to cached background processes; // we have no limit on the number of service, visible, foreground, or other such // processes and the number of those processes does not count against the cached - // process limit. - public int CUR_MAX_CACHED_PROCESSES = DEFAULT_MAX_CACHED_PROCESSES; + // process limit. This will be initialized in the constructor. + public int CUR_MAX_CACHED_PROCESSES; - // The maximum number of empty app processes we will let sit around. - public int CUR_MAX_EMPTY_PROCESSES = computeEmptyProcessLimit(CUR_MAX_CACHED_PROCESSES); + // The maximum number of empty app processes we will let sit around. This will be + // initialized in the constructor. + public int CUR_MAX_EMPTY_PROCESSES; // The number of empty apps at which we don't consider it necessary to do // memory trimming. @@ -762,6 +764,10 @@ final class ActivityManagerConstants extends ContentObserver { context.getResources().getStringArray( com.android.internal.R.array.config_keep_warming_services)) .map(ComponentName::unflattenFromString).collect(Collectors.toSet())); + mCustomizedMaxCachedProcesses = context.getResources().getInteger( + com.android.internal.R.integer.config_customizedMaxCachedProcesses); + CUR_MAX_CACHED_PROCESSES = mCustomizedMaxCachedProcesses; + CUR_MAX_EMPTY_PROCESSES = computeEmptyProcessLimit(CUR_MAX_CACHED_PROCESSES); } public void start(ContentResolver resolver) { @@ -1105,13 +1111,13 @@ final class ActivityManagerConstants extends ContentObserver { try { CUR_MAX_CACHED_PROCESSES = mOverrideMaxCachedProcesses < 0 ? (TextUtils.isEmpty(maxCachedProcessesFlag) - ? DEFAULT_MAX_CACHED_PROCESSES : Integer.parseInt(maxCachedProcessesFlag)) + ? mCustomizedMaxCachedProcesses : Integer.parseInt(maxCachedProcessesFlag)) : mOverrideMaxCachedProcesses; } catch (NumberFormatException e) { // Bad flag value from Phenotype, revert to default. Slog.e(TAG, "Unable to parse flag for max_cached_processes: " + maxCachedProcessesFlag, e); - CUR_MAX_CACHED_PROCESSES = DEFAULT_MAX_CACHED_PROCESSES; + CUR_MAX_CACHED_PROCESSES = mCustomizedMaxCachedProcesses; } CUR_MAX_EMPTY_PROCESSES = computeEmptyProcessLimit(CUR_MAX_CACHED_PROCESSES); @@ -1288,6 +1294,7 @@ final class ActivityManagerConstants extends ContentObserver { if (mOverrideMaxCachedProcesses >= 0) { pw.print(" mOverrideMaxCachedProcesses="); pw.println(mOverrideMaxCachedProcesses); } + pw.print(" mCustomizedMaxCachedProcesses="); pw.println(mCustomizedMaxCachedProcesses); pw.print(" CUR_MAX_CACHED_PROCESSES="); pw.println(CUR_MAX_CACHED_PROCESSES); pw.print(" CUR_MAX_EMPTY_PROCESSES="); pw.println(CUR_MAX_EMPTY_PROCESSES); pw.print(" CUR_TRIM_EMPTY_PROCESSES="); pw.println(CUR_TRIM_EMPTY_PROCESSES); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 0d35bb180514..4ec5559a061d 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -16120,10 +16120,10 @@ public class ActivityManagerService extends IActivityManager.Stub @Override public ServiceNotificationPolicy applyForegroundServiceNotification( - Notification notification, int id, String pkg, int userId) { + Notification notification, String tag, int id, String pkg, int userId) { synchronized (ActivityManagerService.this) { return mServices.applyForegroundServiceNotificationLocked(notification, - id, pkg, userId); + tag, id, pkg, userId); } } diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java index 67dfb8051f93..0c633cacda92 100644 --- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java +++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java @@ -579,8 +579,10 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync { } } - // Collect the latest low power stats without holding the mStats lock. - mStats.fillLowPowerStats(); + if ((updateFlags & BatteryStatsImpl.ExternalStatsSync.UPDATE_RPM) != 0) { + // Collect the latest low power stats without holding the mStats lock. + mStats.fillLowPowerStats(); + } final WifiActivityEnergyInfo wifiInfo = awaitControllerInfo(wifiReceiver); final BluetoothActivityEnergyInfo bluetoothInfo = awaitControllerInfo(bluetoothReceiver); diff --git a/services/core/java/com/android/server/app/GameManagerService.java b/services/core/java/com/android/server/app/GameManagerService.java index ae1cd51e11f0..af8d7a6a282b 100644 --- a/services/core/java/com/android/server/app/GameManagerService.java +++ b/services/core/java/com/android/server/app/GameManagerService.java @@ -37,6 +37,7 @@ import static com.android.server.wm.CompatModePackages.DOWNSCALE_90; import android.Manifest; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.app.ActivityManager; import android.app.GameManager; @@ -73,6 +74,7 @@ import com.android.internal.compat.CompatibilityOverrideConfig; import com.android.internal.compat.IPlatformCompat; import com.android.server.ServiceThread; import com.android.server.SystemService; +import com.android.server.SystemService.TargetUser; import java.io.FileDescriptor; import java.util.List; @@ -196,6 +198,7 @@ public final class GameManagerService extends IGameManagerService.Stub { final int userId = (int) msg.obj; final String[] packageNames = getInstalledGamePackageNames(userId); updateConfigsForUser(userId, packageNames); + break; } } } @@ -212,7 +215,7 @@ public final class GameManagerService extends IGameManagerService.Stub { @Override public void onPropertiesChanged(Properties properties) { final String[] packageNames = properties.getKeyset().toArray(new String[0]); - updateConfigsForUser(mContext.getUserId(), packageNames); + updateConfigsForUser(ActivityManager.getCurrentUser(), packageNames); } @Override @@ -496,6 +499,11 @@ public final class GameManagerService extends IGameManagerService.Stub { public void onUserStopping(@NonNull TargetUser user) { mService.onUserStopping(user.getUserIdentifier()); } + + @Override + public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) { + mService.onUserSwitching(from, to.getUserIdentifier()); + } } private boolean isValidPackageName(String packageName, int userId) { @@ -503,7 +511,6 @@ public final class GameManagerService extends IGameManagerService.Stub { return mPackageManager.getPackageUidAsUser(packageName, userId) == Binder.getCallingUid(); } catch (PackageManager.NameNotFoundException e) { - e.printStackTrace(); return false; } } @@ -567,7 +574,6 @@ public final class GameManagerService extends IGameManagerService.Stub { return GameManager.GAME_MODE_UNSUPPORTED; } } catch (PackageManager.NameNotFoundException e) { - e.printStackTrace(); return GameManager.GAME_MODE_UNSUPPORTED; } @@ -606,7 +612,6 @@ public final class GameManagerService extends IGameManagerService.Stub { return; } } catch (PackageManager.NameNotFoundException e) { - e.printStackTrace(); return; } @@ -639,14 +644,12 @@ public final class GameManagerService extends IGameManagerService.Stub { void onUserStarting(int userId) { synchronized (mLock) { - if (mSettings.containsKey(userId)) { - return; + if (!mSettings.containsKey(userId)) { + GameManagerSettings userSettings = + new GameManagerSettings(Environment.getDataSystemDeDirectory(userId)); + mSettings.put(userId, userSettings); + userSettings.readPersistentDataLocked(); } - - GameManagerSettings userSettings = - new GameManagerSettings(Environment.getDataSystemDeDirectory(userId)); - mSettings.put(userId, userSettings); - userSettings.readPersistentDataLocked(); } final Message msg = mHandler.obtainMessage(POPULATE_GAME_MODE_SETTINGS); msg.obj = userId; @@ -664,6 +667,22 @@ public final class GameManagerService extends IGameManagerService.Stub { } } + void onUserSwitching(TargetUser from, int toUserId) { + if (from != null) { + synchronized (mLock) { + final int fromUserId = from.getUserIdentifier(); + if (mSettings.containsKey(fromUserId)) { + final Message msg = mHandler.obtainMessage(REMOVE_SETTINGS); + msg.obj = fromUserId; + mHandler.sendMessage(msg); + } + } + } + final Message msg = mHandler.obtainMessage(POPULATE_GAME_MODE_SETTINGS); + msg.obj = toUserId; + mHandler.sendMessage(msg); + } + /** * @hide */ @@ -856,11 +875,25 @@ public final class GameManagerService extends IGameManagerService.Stub { public void onReceive(@NonNull final Context context, @NonNull final Intent intent) { final Uri data = intent.getData(); try { + final int userId = getSendingUserId(); + if (userId != ActivityManager.getCurrentUser()) { + return; + } final String packageName = data.getSchemeSpecificPart(); + try { + final ApplicationInfo applicationInfo = mPackageManager + .getApplicationInfoAsUser( + packageName, PackageManager.MATCH_ALL, userId); + if (applicationInfo.category != ApplicationInfo.CATEGORY_GAME) { + return; + } + } catch (PackageManager.NameNotFoundException e) { + // Ignore the exception. + } switch (intent.getAction()) { case ACTION_PACKAGE_ADDED: case ACTION_PACKAGE_CHANGED: - updateConfigsForUser(mContext.getUserId(), packageName); + updateConfigsForUser(userId, packageName); break; case ACTION_PACKAGE_REMOVED: disableCompatScale(packageName); @@ -873,11 +906,12 @@ public final class GameManagerService extends IGameManagerService.Stub { break; } } catch (NullPointerException e) { - Slog.e(TAG, "Failed to get package name for new package", e); + Slog.e(TAG, "Failed to get package name for new package"); } } }; - mContext.registerReceiver(packageReceiver, packageFilter); + mContext.registerReceiverForAllUsers(packageReceiver, packageFilter, + /* broadcastPermission= */ null, /* scheduler= */ null); } private void registerDeviceConfigListener() { diff --git a/services/core/java/com/android/server/apphibernation/AppHibernationService.java b/services/core/java/com/android/server/apphibernation/AppHibernationService.java index 7f1402d83a0c..db2ecc54dbfe 100644 --- a/services/core/java/com/android/server/apphibernation/AppHibernationService.java +++ b/services/core/java/com/android/server/apphibernation/AppHibernationService.java @@ -849,7 +849,7 @@ public final class AppHibernationService extends SystemService { return DeviceConfig.getBoolean( NAMESPACE_APP_HIBERNATION, KEY_APP_HIBERNATION_ENABLED, - false /* defaultValue */); + true /* defaultValue */); } /** diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index 7789d604461c..33bc212fb9c0 100644 --- a/services/core/java/com/android/server/appop/AppOpsService.java +++ b/services/core/java/com/android/server/appop/AppOpsService.java @@ -1090,8 +1090,7 @@ public class AppOpsService extends IAppOpsService.Stub { */ private void finishOrPause(@NonNull IBinder clientId, boolean triggerCallbackIfNeeded, boolean isPausing) { - int indexOfToken = mInProgressEvents != null - ? mInProgressEvents.indexOfKey(clientId) : -1; + int indexOfToken = isRunning() ? mInProgressEvents.indexOfKey(clientId) : -1; if (indexOfToken < 0) { finishPossiblyPaused(clientId, isPausing); return; @@ -1145,7 +1144,7 @@ public class AppOpsService extends IAppOpsService.Stub { // Finish or pause (no-op) an already paused op private void finishPossiblyPaused(@NonNull IBinder clientId, boolean isPausing) { - if (mPausedInProgressEvents == null) { + if (!isPaused()) { Slog.wtf(TAG, "No ops running or paused"); return; } @@ -1186,7 +1185,7 @@ public class AppOpsService extends IAppOpsService.Stub { * Pause all currently started ops. This will create a HistoricalRegistry */ public void pause() { - if (mInProgressEvents == null) { + if (!isRunning()) { return; } @@ -1211,7 +1210,7 @@ public class AppOpsService extends IAppOpsService.Stub { * times, but keep all other values the same */ public void resume() { - if (mPausedInProgressEvents == null) { + if (!isPaused()) { return; } @@ -1245,7 +1244,7 @@ public class AppOpsService extends IAppOpsService.Stub { */ void onClientDeath(@NonNull IBinder clientId) { synchronized (AppOpsService.this) { - if (mInProgressEvents == null && mPausedInProgressEvents == null) { + if (!isPaused() && !isRunning()) { return; } @@ -1266,7 +1265,7 @@ public class AppOpsService extends IAppOpsService.Stub { * @param newState The new state */ public void onUidStateChanged(@AppOpsManager.UidState int newState) { - if (mInProgressEvents == null && mPausedInProgressEvents == null) { + if (!isPaused() && !isRunning()) { return; } @@ -1350,12 +1349,15 @@ public class AppOpsService extends IAppOpsService.Stub { * @param opToAdd The op to add */ public void add(@NonNull AttributedOp opToAdd) { - if (opToAdd.mInProgressEvents != null) { - Slog.w(TAG, "Ignoring " + opToAdd.mInProgressEvents.size() + " running app-ops"); + if (opToAdd.isRunning() || opToAdd.isPaused()) { + ArrayMap<IBinder, InProgressStartOpEvent> ignoredEvents = opToAdd.isRunning() + ? opToAdd.mInProgressEvents : opToAdd.mPausedInProgressEvents; + Slog.w(TAG, "Ignoring " + ignoredEvents.size() + " app-ops, running: " + + opToAdd.isRunning()); - int numInProgressEvents = opToAdd.mInProgressEvents.size(); + int numInProgressEvents = ignoredEvents.size(); for (int i = 0; i < numInProgressEvents; i++) { - InProgressStartOpEvent event = opToAdd.mInProgressEvents.valueAt(i); + InProgressStartOpEvent event = ignoredEvents.valueAt(i); event.finish(); mInProgressStartOpEventPool.release(event); @@ -1367,11 +1369,11 @@ public class AppOpsService extends IAppOpsService.Stub { } public boolean isRunning() { - return mInProgressEvents != null; + return mInProgressEvents != null && !mInProgressEvents.isEmpty(); } public boolean isPaused() { - return mPausedInProgressEvents != null; + return mPausedInProgressEvents != null && !mPausedInProgressEvents.isEmpty(); } boolean hasAnyTime() { @@ -1401,7 +1403,7 @@ public class AppOpsService extends IAppOpsService.Stub { LongSparseArray<NoteOpEvent> accessEvents = deepClone(mAccessEvents); // Add in progress events as access events - if (mInProgressEvents != null) { + if (isRunning()) { long now = SystemClock.elapsedRealtime(); int numInProgressEvents = mInProgressEvents.size(); @@ -2041,9 +2043,12 @@ public class AppOpsService extends IAppOpsService.Stub { attributionNum++) { AttributedOp attributedOp = op.mAttributions.valueAt(attributionNum); - while (attributedOp.mInProgressEvents != null) { + while (attributedOp.isRunning()) { attributedOp.finished(attributedOp.mInProgressEvents.keyAt(0)); } + while (attributedOp.isPaused()) { + attributedOp.finished(attributedOp.mPausedInProgressEvents.keyAt(0)); + } } } } diff --git a/services/core/java/com/android/server/audio/RecordingActivityMonitor.java b/services/core/java/com/android/server/audio/RecordingActivityMonitor.java index ea0107ecfd23..26a63120d793 100644 --- a/services/core/java/com/android/server/audio/RecordingActivityMonitor.java +++ b/services/core/java/com/android/server/audio/RecordingActivityMonitor.java @@ -594,6 +594,7 @@ public final class RecordingActivityMonitor implements AudioSystem.AudioRecordin private final int mSession; private final int mSource; private final String mPackName; + private final boolean mSilenced; RecordingEvent(int event, int riid, AudioRecordingConfiguration config) { mRecEvent = event; @@ -603,11 +604,13 @@ public final class RecordingActivityMonitor implements AudioSystem.AudioRecordin mSession = config.getClientAudioSessionId(); mSource = config.getClientAudioSource(); mPackName = config.getClientPackageName(); + mSilenced = config.isClientSilenced(); } else { mClientUid = -1; mSession = -1; mSource = -1; mPackName = null; + mSilenced = false; } } @@ -633,6 +636,7 @@ public final class RecordingActivityMonitor implements AudioSystem.AudioRecordin .append(" uid:").append(mClientUid) .append(" session:").append(mSession) .append(" src:").append(MediaRecorder.toLogFriendlyAudioSource(mSource)) + .append(mSilenced ? " silenced" : " not silenced") .append(mPackName == null ? "" : " pack:" + mPackName).toString(); } } diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java index 45e93a096550..5e1a245554a6 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java @@ -30,13 +30,14 @@ import android.util.Slog; import com.android.server.biometrics.BiometricsProto; import com.android.server.biometrics.sensors.AcquisitionClient; import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter; +import com.android.server.biometrics.sensors.DetectionConsumer; import com.android.server.biometrics.sensors.fingerprint.UdfpsHelper; /** * Performs fingerprint detection without exposing any matching information (e.g. accept/reject * have the same haptic, lockout counter is not increased). */ -class FingerprintDetectClient extends AcquisitionClient<ISession> { +class FingerprintDetectClient extends AcquisitionClient<ISession> implements DetectionConsumer { private static final String TAG = "FingerprintDetectClient"; @@ -88,7 +89,8 @@ class FingerprintDetectClient extends AcquisitionClient<ISession> { } } - void onInteractionDetected() { + @Override + public void onInteractionDetected() { vibrateSuccess(); try { diff --git a/services/core/java/com/android/server/compat/overrides/AppCompatOverridesParser.java b/services/core/java/com/android/server/compat/overrides/AppCompatOverridesParser.java new file mode 100644 index 000000000000..a81213df6fe3 --- /dev/null +++ b/services/core/java/com/android/server/compat/overrides/AppCompatOverridesParser.java @@ -0,0 +1,383 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.compat.overrides; + +import static android.content.pm.PackageManager.MATCH_ANY_USER; + +import static java.util.Collections.emptyMap; +import static java.util.Collections.emptySet; + +import android.app.compat.PackageOverride; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.util.ArrayMap; +import android.util.ArraySet; +import android.util.KeyValueListParser; +import android.util.Slog; + +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.regex.Pattern; + +/** + * A utility class for parsing App Compat Overrides flags. + * + * @hide + */ +final class AppCompatOverridesParser { + /** + * Flag for specifying all compat change IDs owned by a namespace. See {@link + * #parseOwnedChangeIds} for information on how this flag is parsed. + */ + static final String FLAG_OWNED_CHANGE_IDS = "owned_change_ids"; + + /** + * Flag for immediately removing overrides for certain packages and change IDs (from the compat + * platform), as well as stopping to apply them, in case of an emergency. See {@link + * #parseRemoveOverrides} for information on how this flag is parsed. + */ + static final String FLAG_REMOVE_OVERRIDES = "remove_overrides"; + + private static final String TAG = "AppCompatOverridesParser"; + + private static final String WILDCARD_SYMBOL = "*"; + + private static final Pattern BOOLEAN_PATTERN = + Pattern.compile("true|false", Pattern.CASE_INSENSITIVE); + + private static final String WILDCARD_NO_OWNED_CHANGE_IDS_WARNING = + "Wildcard can't be used in '" + FLAG_REMOVE_OVERRIDES + "' flag with an empty " + + FLAG_OWNED_CHANGE_IDS + "' flag"; + + private final PackageManager mPackageManager; + + AppCompatOverridesParser(PackageManager packageManager) { + mPackageManager = packageManager; + } + + /** + * Parses the given {@code configStr} and returns a map from package name to a set of change + * IDs to remove for that package. + * + * <p>The given {@code configStr} is expected to either be: + * + * <ul> + * <li>'*' (wildcard), to indicate that all owned overrides, specified in {@code + * ownedChangeIds}, for all installed packages should be removed. + * <li>A comma separated key value list, where the key is a package name and the value is + * either: + * <ul> + * <li>'*' (wildcard), to indicate that all owned overrides, specified in {@code + * ownedChangeIds} for that package should be removed. + * <li>A colon separated list of change IDs to remove for that package. + * </ul> + * </ul> + * + * <p>If the given {@code configStr} doesn't match the expected format, an empty map will be + * returned. If a specific change ID isn't a valid long, it will be ignored. + */ + Map<String, Set<Long>> parseRemoveOverrides(String configStr, Set<Long> ownedChangeIds) { + if (configStr.isEmpty()) { + return emptyMap(); + } + + Map<String, Set<Long>> result = new ArrayMap<>(); + if (configStr.equals(WILDCARD_SYMBOL)) { + if (ownedChangeIds.isEmpty()) { + Slog.w(TAG, WILDCARD_NO_OWNED_CHANGE_IDS_WARNING); + return emptyMap(); + } + List<ApplicationInfo> installedApps = mPackageManager.getInstalledApplications( + MATCH_ANY_USER); + for (ApplicationInfo appInfo : installedApps) { + result.put(appInfo.packageName, ownedChangeIds); + } + return result; + } + + KeyValueListParser parser = new KeyValueListParser(','); + try { + parser.setString(configStr); + } catch (IllegalArgumentException e) { + Slog.w( + TAG, + "Invalid format in '" + FLAG_REMOVE_OVERRIDES + "' flag: " + configStr, e); + return emptyMap(); + } + for (int i = 0; i < parser.size(); i++) { + String packageName = parser.keyAt(i); + String changeIdsStr = parser.getString(packageName, /* def= */ ""); + if (changeIdsStr.equals(WILDCARD_SYMBOL)) { + if (ownedChangeIds.isEmpty()) { + Slog.w(TAG, WILDCARD_NO_OWNED_CHANGE_IDS_WARNING); + continue; + } + result.put(packageName, ownedChangeIds); + } else { + for (String changeIdStr : changeIdsStr.split(":")) { + try { + long changeId = Long.parseLong(changeIdStr); + result.computeIfAbsent(packageName, k -> new ArraySet<>()).add(changeId); + } catch (NumberFormatException e) { + Slog.w( + TAG, + "Invalid change ID in '" + FLAG_REMOVE_OVERRIDES + "' flag: " + + changeIdStr, e); + } + } + } + } + + return result; + } + + + /** + * Parses the given {@code configStr}, that is expected to be a comma separated list of change + * IDs, into a set. + * + * <p>If any of the change IDs isn't a valid long, it will be ignored. + */ + static Set<Long> parseOwnedChangeIds(String configStr) { + if (configStr.isEmpty()) { + return emptySet(); + } + + Set<Long> result = new ArraySet<>(); + for (String changeIdStr : configStr.split(",")) { + try { + result.add(Long.parseLong(changeIdStr)); + } catch (NumberFormatException e) { + Slog.w(TAG, + "Invalid change ID in '" + FLAG_OWNED_CHANGE_IDS + "' flag: " + changeIdStr, + e); + } + } + return result; + } + + /** + * Parses the given {@code configStr}, that is expected to be a comma separated list of changes + * overrides, and returns a {@link PackageOverrides}. + * + * <p>Each change override is in the following format: + * '<change-id>:<min-version-code?>:<max-version-code?>:<enabled?>'. If <enabled> is empty, + * this indicates that any override for the specified change ID should be removed. + * + * <p>If there are multiple overrides that should be added with the same change ID, the one + * that best fits the given {@code versionCode} is added. + * + * <p>Any overrides whose change ID is in {@code changeIdsToSkip} are ignored. + * + * <p>If a change override entry in {@code configStr} is invalid, it will be ignored. If the + * same change ID is both added and removed, i.e., has a change override entry with an empty + * enabled and another with a non-empty enabled, the change ID will only be removed. + */ + static PackageOverrides parsePackageOverrides( + String configStr, long versionCode, Set<Long> changeIdsToSkip) { + if (configStr.isEmpty()) { + return new PackageOverrides(); + } + PackageOverrideComparator comparator = new PackageOverrideComparator(versionCode); + Map<Long, PackageOverride> overridesToAdd = new ArrayMap<>(); + Set<Long> overridesToRemove = new ArraySet<>(); + for (String overrideEntryString : configStr.split(",")) { + List<String> changeIdAndVersions = Arrays.asList(overrideEntryString.split(":", 4)); + if (changeIdAndVersions.size() != 4) { + Slog.w(TAG, "Invalid change override entry: " + overrideEntryString); + continue; + } + long changeId; + try { + changeId = Long.parseLong(changeIdAndVersions.get(0)); + } catch (NumberFormatException e) { + Slog.w(TAG, "Invalid change ID in override entry: " + overrideEntryString, e); + continue; + } + + if (changeIdsToSkip.contains(changeId)) { + continue; + } + + String minVersionCodeStr = changeIdAndVersions.get(1); + String maxVersionCodeStr = changeIdAndVersions.get(2); + + String enabledStr = changeIdAndVersions.get(3); + if (enabledStr.isEmpty()) { + if (!minVersionCodeStr.isEmpty() || !maxVersionCodeStr.isEmpty()) { + Slog.w( + TAG, + "min/max version code should be empty if enabled is empty: " + + overrideEntryString); + } + overridesToRemove.add(changeId); + continue; + } + if (!BOOLEAN_PATTERN.matcher(enabledStr).matches()) { + Slog.w(TAG, "Invalid enabled string in override entry: " + overrideEntryString); + continue; + } + boolean enabled = Boolean.parseBoolean(enabledStr); + PackageOverride.Builder overrideBuilder = new PackageOverride.Builder().setEnabled( + enabled); + try { + if (!minVersionCodeStr.isEmpty()) { + overrideBuilder.setMinVersionCode(Long.parseLong(minVersionCodeStr)); + } + if (!maxVersionCodeStr.isEmpty()) { + overrideBuilder.setMaxVersionCode(Long.parseLong(maxVersionCodeStr)); + } + } catch (NumberFormatException e) { + Slog.w(TAG, + "Invalid min/max version code in override entry: " + overrideEntryString, + e); + continue; + } + + try { + PackageOverride override = overrideBuilder.build(); + if (!overridesToAdd.containsKey(changeId) + || comparator.compare(override, overridesToAdd.get(changeId)) < 0) { + overridesToAdd.put(changeId, override); + } + } catch (IllegalArgumentException e) { + Slog.w(TAG, "Failed to build PackageOverride", e); + } + } + + for (Long changeId : overridesToRemove) { + if (overridesToAdd.containsKey(changeId)) { + Slog.w( + TAG, + "Change ID [" + + changeId + + "] is both added and removed in package override flag: " + + configStr); + overridesToAdd.remove(changeId); + } + } + + return new PackageOverrides(overridesToAdd, overridesToRemove); + } + + /** + * A container for a map from change ID to {@link PackageOverride} to add and a set of change + * IDs to remove overrides for. + * + * <p>The map of overrides to add and the set of overrides to remove are mutually exclusive. + */ + static final class PackageOverrides { + public final Map<Long, PackageOverride> overridesToAdd; + public final Set<Long> overridesToRemove; + + PackageOverrides() { + this(emptyMap(), emptySet()); + } + + PackageOverrides(Map<Long, PackageOverride> overridesToAdd, Set<Long> overridesToRemove) { + this.overridesToAdd = overridesToAdd; + this.overridesToRemove = overridesToRemove; + } + } + + /** + * A {@link Comparator} that compares @link PackageOverride} instances with respect to a + * specified {@code versionCode} as follows: + * + * <ul> + * <li>Prefer the {@link PackageOverride} whose version range contains {@code versionCode}. + * <li>Otherwise, prefer the {@link PackageOverride} whose version range is closest to {@code + * versionCode} from below. + * <li>Otherwise, prefer the {@link PackageOverride} whose version range is closest to {@code + * versionCode} from above. + * </ul> + */ + private static final class PackageOverrideComparator implements Comparator<PackageOverride> { + private final long mVersionCode; + + PackageOverrideComparator(long versionCode) { + this.mVersionCode = versionCode; + } + + @Override + public int compare(PackageOverride o1, PackageOverride o2) { + // Prefer overrides whose version range contains versionCode. + boolean isVersionInRange1 = isVersionInRange(o1, mVersionCode); + boolean isVersionInRange2 = isVersionInRange(o2, mVersionCode); + if (isVersionInRange1 != isVersionInRange2) { + return isVersionInRange1 ? -1 : 1; + } + + // Otherwise, prefer overrides whose version range is before versionCode. + boolean isVersionAfterRange1 = isVersionAfterRange(o1, mVersionCode); + boolean isVersionAfterRange2 = isVersionAfterRange(o2, mVersionCode); + if (isVersionAfterRange1 != isVersionAfterRange2) { + return isVersionAfterRange1 ? -1 : 1; + } + + // If both overrides' version ranges are either before or after versionCode, prefer + // those whose version range is closer to versionCode. + return Long.compare( + getVersionProximity(o1, mVersionCode), getVersionProximity(o2, mVersionCode)); + } + + /** + * Returns true if the version range in the given {@code override} contains {@code + * versionCode}. + */ + private static boolean isVersionInRange(PackageOverride override, long versionCode) { + return override.getMinVersionCode() <= versionCode + && versionCode <= override.getMaxVersionCode(); + } + + /** + * Returns true if the given {@code versionCode} is strictly after the version range in the + * given {@code override}. + */ + private static boolean isVersionAfterRange(PackageOverride override, long versionCode) { + return override.getMaxVersionCode() < versionCode; + } + + /** + * Returns true if the given {@code versionCode} is strictly before the version range in the + * given {@code override}. + */ + private static boolean isVersionBeforeRange(PackageOverride override, long versionCode) { + return override.getMinVersionCode() > versionCode; + } + + /** + * In case the given {@code versionCode} is strictly before or after the version range in + * the given {@code override}, returns the distance from it, otherwise returns zero. + */ + private static long getVersionProximity(PackageOverride override, long versionCode) { + if (isVersionAfterRange(override, versionCode)) { + return versionCode - override.getMaxVersionCode(); + } + if (isVersionBeforeRange(override, versionCode)) { + return override.getMinVersionCode() - versionCode; + } + + // Version is in range. Note that when two overrides have a zero version proximity + // they will be ordered arbitrarily. + return 0; + } + } +} diff --git a/services/core/java/com/android/server/compat/overrides/AppCompatOverridesService.java b/services/core/java/com/android/server/compat/overrides/AppCompatOverridesService.java new file mode 100644 index 000000000000..63ae1af42f08 --- /dev/null +++ b/services/core/java/com/android/server/compat/overrides/AppCompatOverridesService.java @@ -0,0 +1,408 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.compat.overrides; + +import static android.content.Intent.ACTION_PACKAGE_ADDED; +import static android.content.Intent.ACTION_PACKAGE_CHANGED; +import static android.content.Intent.ACTION_PACKAGE_REMOVED; +import static android.content.pm.PackageManager.MATCH_ANY_USER; +import static android.provider.DeviceConfig.NAMESPACE_APP_COMPAT_OVERRIDES; + +import static com.android.server.compat.overrides.AppCompatOverridesParser.FLAG_OWNED_CHANGE_IDS; +import static com.android.server.compat.overrides.AppCompatOverridesParser.FLAG_REMOVE_OVERRIDES; + +import static java.util.Collections.emptySet; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.compat.PackageOverride; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.net.Uri; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.provider.DeviceConfig; +import android.provider.DeviceConfig.Properties; +import android.util.ArraySet; +import android.util.Slog; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.compat.CompatibilityOverrideConfig; +import com.android.internal.compat.CompatibilityOverridesToRemoveConfig; +import com.android.internal.compat.IPlatformCompat; +import com.android.server.SystemService; +import com.android.server.compat.overrides.AppCompatOverridesParser.PackageOverrides; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * Service for applying per-app compat overrides delivered via Device Config. + * + * <p>The service listens both on changes to supported Device Config namespaces and on package + * added/changed/removed events, and applies overrides accordingly. + * + * @hide + */ +public final class AppCompatOverridesService { + private static final String TAG = "AppCompatOverridesService"; + + private static final List<String> SUPPORTED_NAMESPACES = Arrays.asList( + NAMESPACE_APP_COMPAT_OVERRIDES); + + private final Context mContext; + private final PackageManager mPackageManager; + private final IPlatformCompat mPlatformCompat; + private final List<String> mSupportedNamespaces; + private final AppCompatOverridesParser mOverridesParser; + private final PackageReceiver mPackageReceiver; + private final List<DeviceConfigListener> mDeviceConfigListeners; + + private AppCompatOverridesService(Context context) { + this(context, IPlatformCompat.Stub.asInterface( + ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE)), SUPPORTED_NAMESPACES); + } + + @VisibleForTesting + AppCompatOverridesService(Context context, IPlatformCompat platformCompat, + List<String> supportedNamespaces) { + mContext = context; + mPackageManager = mContext.getPackageManager(); + mPlatformCompat = platformCompat; + mSupportedNamespaces = supportedNamespaces; + mOverridesParser = new AppCompatOverridesParser(mPackageManager); + mPackageReceiver = new PackageReceiver(mContext); + mDeviceConfigListeners = new ArrayList<>(); + for (String namespace : mSupportedNamespaces) { + mDeviceConfigListeners.add(new DeviceConfigListener(mContext, namespace)); + } + } + + @Override + public void finalize() { + unregisterDeviceConfigListeners(); + unregisterPackageReceiver(); + } + + @VisibleForTesting + void registerDeviceConfigListeners() { + for (DeviceConfigListener listener : mDeviceConfigListeners) { + listener.register(); + } + } + + private void unregisterDeviceConfigListeners() { + for (DeviceConfigListener listener : mDeviceConfigListeners) { + listener.unregister(); + } + } + + @VisibleForTesting + void registerPackageReceiver() { + mPackageReceiver.register(); + } + + private void unregisterPackageReceiver() { + mPackageReceiver.unregister(); + } + + /** + * Same as {@link #applyOverrides(Properties, Map)} except all properties of the given {@code + * namespace} are fetched via {@link DeviceConfig#getProperties}. + */ + private void applyAllOverrides(String namespace, + Map<String, Set<Long>> packageToChangeIdsToSkip) { + applyOverrides(DeviceConfig.getProperties(namespace), packageToChangeIdsToSkip); + } + + /** + * Iterates all package override flags in the given {@code properties}, and for each flag whose + * package is installed on the device, parses its value and applies the overrides in it with + * respect to the package's current installed version. + */ + private void applyOverrides(Properties properties, + Map<String, Set<Long>> packageToChangeIdsToSkip) { + Set<String> packageNames = new ArraySet<>(properties.getKeyset()); + packageNames.remove(FLAG_OWNED_CHANGE_IDS); + packageNames.remove(FLAG_REMOVE_OVERRIDES); + for (String packageName : packageNames) { + Long versionCode = getVersionCodeOrNull(packageName); + if (versionCode == null) { + // Package isn't installed yet. + continue; + } + + applyPackageOverrides(properties.getString(packageName, /* defaultValue= */ ""), + packageName, versionCode, + packageToChangeIdsToSkip.getOrDefault(packageName, emptySet())); + } + } + + /** + * Applies all overrides in all supported namespaces for the given {@code packageName}. + */ + private void applyAllPackageOverrides(String packageName) { + Long versionCode = getVersionCodeOrNull(packageName); + if (versionCode == null) { + return; + } + + for (String namespace : mSupportedNamespaces) { + // We apply overrides for each namespace separately so that if there is a failure for + // one namespace, the other namespaces won't be affected. + applyPackageOverrides( + DeviceConfig.getString(namespace, packageName, /* defaultValue= */ ""), + packageName, versionCode, + getOverridesToRemove(namespace).getOrDefault(packageName, emptySet())); + } + } + + /** + * Calls {@link AppCompatOverridesParser#parsePackageOverrides} on the given arguments, adds the + * resulting {@link PackageOverrides#overridesToAdd} via {@link + * IPlatformCompat#putOverridesOnReleaseBuilds}, and removes the resulting {@link + * PackageOverrides#overridesToRemove} via {@link + * IPlatformCompat#removeOverridesOnReleaseBuilds}. + */ + private void applyPackageOverrides(String configStr, String packageName, + long versionCode, Set<Long> changeIdsToSkip) { + PackageOverrides packageOverrides = AppCompatOverridesParser.parsePackageOverrides( + configStr, versionCode, changeIdsToSkip); + putPackageOverrides(packageName, packageOverrides.overridesToAdd); + removePackageOverrides(packageName, packageOverrides.overridesToRemove); + } + + /** + * Removes all owned overrides in all supported namespaces for the given {@code packageName}. + * + * <p>If a certain namespace doesn't have a package override flag for the given {@code + * packageName}, that namespace is skipped.</p> + */ + private void removeAllPackageOverrides(String packageName) { + for (String namespace : mSupportedNamespaces) { + if (DeviceConfig.getString(namespace, packageName, /* defaultValue= */ "").isEmpty()) { + // No overrides for this package in this namespace. + continue; + } + // We remove overrides for each namespace separately so that if there is a failure for + // one namespace, the other namespaces won't be affected. + removePackageOverrides(packageName, getOwnedChangeIds(namespace)); + } + } + + /** + * Calls {@link IPlatformCompat#removeOverridesOnReleaseBuilds} on each package name and + * respective change IDs in {@code overridesToRemove}. + */ + private void removeOverrides(Map<String, Set<Long>> overridesToRemove) { + for (Map.Entry<String, Set<Long>> packageNameAndOverrides : overridesToRemove.entrySet()) { + removePackageOverrides(packageNameAndOverrides.getKey(), + packageNameAndOverrides.getValue()); + } + } + + /** + * Fetches the value of {@link AppCompatOverridesParser#FLAG_REMOVE_OVERRIDES} for the given + * {@code namespace} and parses it into a map from package name to a set of change IDs to + * remove for that package. + */ + private Map<String, Set<Long>> getOverridesToRemove(String namespace) { + return mOverridesParser.parseRemoveOverrides( + DeviceConfig.getString(namespace, FLAG_REMOVE_OVERRIDES, /* defaultValue= */ ""), + getOwnedChangeIds(namespace)); + } + + /** + * Fetches the value of {@link AppCompatOverridesParser#FLAG_OWNED_CHANGE_IDS} for the given + * {@code namespace} and parses it into a set of change IDs. + */ + private static Set<Long> getOwnedChangeIds(String namespace) { + return AppCompatOverridesParser.parseOwnedChangeIds( + DeviceConfig.getString(namespace, FLAG_OWNED_CHANGE_IDS, /* defaultValue= */ "")); + } + + private void putPackageOverrides(String packageName, + Map<Long, PackageOverride> overridesToAdd) { + if (overridesToAdd.isEmpty()) { + return; + } + CompatibilityOverrideConfig config = new CompatibilityOverrideConfig(overridesToAdd); + try { + mPlatformCompat.putOverridesOnReleaseBuilds(config, packageName); + } catch (RemoteException e) { + Slog.w(TAG, "Failed to call IPlatformCompat#putOverridesOnReleaseBuilds", e); + } + } + + private void removePackageOverrides(String packageName, Set<Long> overridesToRemove) { + if (overridesToRemove.isEmpty()) { + return; + } + CompatibilityOverridesToRemoveConfig config = new CompatibilityOverridesToRemoveConfig( + overridesToRemove); + try { + mPlatformCompat.removeOverridesOnReleaseBuilds(config, packageName); + } catch (RemoteException e) { + Slog.w(TAG, "Failed to call IPlatformCompat#removeOverridesOnReleaseBuilds", e); + } + } + + private boolean isInstalledForAnyUser(String packageName) { + return getVersionCodeOrNull(packageName) != null; + } + + @Nullable + private Long getVersionCodeOrNull(String packageName) { + try { + ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(packageName, + MATCH_ANY_USER); + return applicationInfo.longVersionCode; + } catch (PackageManager.NameNotFoundException e) { + // Package isn't installed for any user. + return null; + } + } + + /** + * SystemService lifecycle for AppCompatOverridesService. + * + * @hide + */ + public static final class Lifecycle extends SystemService { + private AppCompatOverridesService mService; + + public Lifecycle(Context context) { + super(context); + } + + @Override + public void onStart() { + mService = new AppCompatOverridesService(getContext()); + mService.registerDeviceConfigListeners(); + mService.registerPackageReceiver(); + } + } + + /** + * A {@link DeviceConfig.OnPropertiesChangedListener} that listens on changes to a given + * namespace and adds/removes overrides according to the changed flags. + */ + private final class DeviceConfigListener implements DeviceConfig.OnPropertiesChangedListener { + private final Context mContext; + private final String mNamespace; + + private DeviceConfigListener(Context context, String namespace) { + mContext = context; + mNamespace = namespace; + } + + private void register() { + DeviceConfig.addOnPropertiesChangedListener(mNamespace, mContext.getMainExecutor(), + this); + } + + private void unregister() { + DeviceConfig.removeOnPropertiesChangedListener(this); + } + + @Override + public void onPropertiesChanged(Properties properties) { + boolean removeOverridesFlagChanged = properties.getKeyset().contains( + FLAG_REMOVE_OVERRIDES); + boolean ownedChangedIdsFlagChanged = properties.getKeyset().contains( + FLAG_OWNED_CHANGE_IDS); + + Map<String, Set<Long>> overridesToRemove = getOverridesToRemove(mNamespace); + if (removeOverridesFlagChanged || ownedChangedIdsFlagChanged) { + // In both cases it's possible that overrides that weren't removed before should + // now be removed. + removeOverrides(overridesToRemove); + } + + if (removeOverridesFlagChanged) { + // We need to re-apply all overrides in the namespace since the remove overrides + // flag might have blocked some of them from being applied before. + applyAllOverrides(mNamespace, overridesToRemove); + } else { + applyOverrides(properties, overridesToRemove); + } + } + } + + /** + * A {@link BroadcastReceiver} that listens on package added/changed/removed events and + * adds/removes overrides according to the corresponding Device Config flags. + */ + private final class PackageReceiver extends BroadcastReceiver { + private final Context mContext; + private final IntentFilter mIntentFilter; + + private PackageReceiver(Context context) { + mContext = context; + mIntentFilter = new IntentFilter(); + mIntentFilter.addAction(ACTION_PACKAGE_ADDED); + mIntentFilter.addAction(ACTION_PACKAGE_CHANGED); + mIntentFilter.addAction(ACTION_PACKAGE_REMOVED); + mIntentFilter.addDataScheme("package"); + } + + private void register() { + mContext.registerReceiverForAllUsers(this, mIntentFilter, /* broadcastPermission= */ + null, /* scheduler= */ null); + } + + private void unregister() { + mContext.unregisterReceiver(this); + } + + @Override + public void onReceive(@NonNull final Context context, @NonNull final Intent intent) { + Uri data = intent.getData(); + if (data == null) { + Slog.w(TAG, "Failed to get package name in package receiver"); + return; + } + String packageName = data.getSchemeSpecificPart(); + String action = intent.getAction(); + if (action == null) { + Slog.w(TAG, "Failed to get action in package receiver"); + return; + } + switch (action) { + case ACTION_PACKAGE_ADDED: + case ACTION_PACKAGE_CHANGED: + applyAllPackageOverrides(packageName); + break; + case ACTION_PACKAGE_REMOVED: + if (!isInstalledForAnyUser(packageName)) { + removeAllPackageOverrides(packageName); + } + break; + default: + Slog.w(TAG, "Unsupported action in package receiver: " + action); + break; + } + } + }; +} diff --git a/services/core/java/com/android/server/compat/overrides/TEST_MAPPING b/services/core/java/com/android/server/compat/overrides/TEST_MAPPING new file mode 100644 index 000000000000..4b8f08ec9164 --- /dev/null +++ b/services/core/java/com/android/server/compat/overrides/TEST_MAPPING @@ -0,0 +1,12 @@ +{ + "presubmit": [ + { + "name": "FrameworksMockingServicesTests", + "options": [ + { + "include-filter": "com.android.server.compat.overrides" + } + ] + } + ] +} diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java index fb919fbe0a3d..53c13c7a1268 100644 --- a/services/core/java/com/android/server/content/SyncManager.java +++ b/services/core/java/com/android/server/content/SyncManager.java @@ -28,7 +28,7 @@ import android.accounts.AccountManagerInternal; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; -import android.app.ActivityManager; +import android.app.ActivityManagerInternal; import android.app.AppGlobals; import android.app.Notification; import android.app.NotificationManager; @@ -323,6 +323,8 @@ public class SyncManager { private final PackageManagerInternal mPackageManagerInternal; + private final ActivityManagerInternal mAmi; + private List<UserInfo> getAllUsers() { return mUserManager.getUsers(); } @@ -643,6 +645,7 @@ public class SyncManager { mAccountManager = (AccountManager) mContext.getSystemService(Context.ACCOUNT_SERVICE); mAccountManagerInternal = LocalServices.getService(AccountManagerInternal.class); mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class); + mAmi = LocalServices.getService(ActivityManagerInternal.class); mAccountManagerInternal.addOnAppPermissionChangeListener((Account account, int uid) -> { // If the UID gained access to the account kick-off syncs lacking account access @@ -1115,15 +1118,11 @@ public class SyncManager { } final int owningUid = syncAdapterInfo.uid; final String owningPackage = syncAdapterInfo.componentName.getPackageName(); - try { - if (ActivityManager.getService().isAppStartModeDisabled(owningUid, owningPackage)) { - Slog.w(TAG, "Not scheduling job " + syncAdapterInfo.uid + ":" - + syncAdapterInfo.componentName - + " -- package not allowed to start"); - return AuthorityInfo.NOT_SYNCABLE; - } - } catch (RemoteException e) { - /* ignore - local call */ + if (mAmi.isAppStartModeDisabled(owningUid, owningPackage)) { + Slog.w(TAG, "Not scheduling job " + syncAdapterInfo.uid + ":" + + syncAdapterInfo.componentName + + " -- package not allowed to start"); + return AuthorityInfo.NOT_SYNCABLE; } if (checkAccountAccess && !canAccessAccount(account, owningPackage, owningUid)) { Log.w(TAG, "Access to " + logSafe(account) + " denied for package " diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java index a4a5f96c7358..cb2cd140677e 100644 --- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java +++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java @@ -778,7 +778,6 @@ class AutomaticBrightnessController { mScreenBrightnessThresholds.getBrighteningThreshold(newScreenAutoBrightness)); mScreenDarkeningThreshold = clampScreenBrightness( mScreenBrightnessThresholds.getDarkeningThreshold(newScreenAutoBrightness)); - mHbmController.onAutoBrightnessChanged(mScreenAutoBrightness); if (sendUpdate) { mCallbacks.updateBrightness(); diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index 9d8ca9a2c26a..7d06d6ea50fa 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -705,10 +705,8 @@ public final class DisplayManagerService extends SystemService { final BrightnessPair brightnessPair = index < 0 ? null : mDisplayBrightnesses.valueAt(index); if (index < 0 || (mDisplayStates.valueAt(index) == state - && BrightnessSynchronizer.floatEquals( - brightnessPair.brightness, brightnessState) - && BrightnessSynchronizer.floatEquals( - brightnessPair.sdrBrightness, sdrBrightnessState))) { + && brightnessPair.brightness == brightnessState + && brightnessPair.sdrBrightness == sdrBrightnessState)) { return; // Display no longer exists or no change. } @@ -1281,6 +1279,11 @@ public final class DisplayManagerService extends SystemService { sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED); scheduleTraversalLocked(false); mPersistentDataStore.saveIfNeeded(); + + DisplayPowerController dpc = mDisplayPowerControllers.get(displayId); + if (dpc != null) { + dpc.onDisplayChanged(); + } } private void handleLogicalDisplayFrameRateOverridesChangedLocked( @@ -1312,11 +1315,6 @@ public final class DisplayManagerService extends SystemService { if (work != null) { mHandler.post(work); } - final int displayId = display.getDisplayIdLocked(); - DisplayPowerController dpc = mDisplayPowerControllers.get(displayId); - if (dpc != null) { - dpc.onDisplayChanged(); - } handleLogicalDisplayChangedLocked(display); } diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index 20d364ea16e2..b6d65197d857 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -511,7 +511,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mSkipScreenOnBrightnessRamp = resources.getBoolean( com.android.internal.R.bool.config_skipScreenOnBrightnessRamp); - mHbmController = createHbmController(); + mHbmController = createHbmControllerLocked(); // Seed the cached brightness saveBrightnessInfo(getScreenBrightnessSetting()); @@ -717,6 +717,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call final String uniqueId = device.getUniqueId(); final DisplayDeviceConfig config = device.getDisplayDeviceConfig(); final IBinder token = device.getDisplayTokenLocked(); + final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked(); mHandler.post(() -> { if (mDisplayDevice == device) { return; @@ -724,7 +725,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mDisplayDevice = device; mUniqueDisplayId = uniqueId; mDisplayDeviceConfig = config; - loadFromDisplayDeviceConfig(token); + loadFromDisplayDeviceConfig(token, info); }); } @@ -765,7 +766,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } } - private void loadFromDisplayDeviceConfig(IBinder token) { + private void loadFromDisplayDeviceConfig(IBinder token, DisplayDeviceInfo info) { // All properties that depend on the associated DisplayDevice and the DDC must be // updated here. loadAmbientLightSensor(); @@ -774,7 +775,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call loadNitsRange(mContext.getResources()); setUpAutoBrightness(mContext.getResources(), mHandler); reloadReduceBrightColours(); - mHbmController.resetHbmData(token, mDisplayDeviceConfig.getHighBrightnessModeData()); + mHbmController.resetHbmData(info.width, info.height, token, + mDisplayDeviceConfig.getHighBrightnessModeData(), mBrightnessSetting); } private void sendUpdatePowerState() { @@ -1343,15 +1345,15 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call if (mHbmController.getHighBrightnessMode() == BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR && ((mBrightnessReason.modifier & BrightnessReason.MODIFIER_DIMMED) == 0 || (mBrightnessReason.modifier & BrightnessReason.MODIFIER_LOW_POWER) == 0)) { + // We want to scale HDR brightness level with the SDR level animateValue = mHbmController.getHdrBrightnessValue(); } final float currentBrightness = mPowerState.getScreenBrightness(); final float currentSdrBrightness = mPowerState.getSdrScreenBrightness(); if (isValidBrightnessValue(animateValue) - && (!BrightnessSynchronizer.floatEquals(animateValue, currentBrightness) - || !BrightnessSynchronizer.floatEquals( - sdrAnimateValue, currentSdrBrightness))) { + && (animateValue != currentBrightness + || sdrAnimateValue != currentSdrBrightness)) { if (initialRampSkip || hasBrightnessBuckets || wasOrWillBeInVr || !isDisplayContentVisible || brightnessIsTemporary) { animateScreenBrightness(animateValue, sdrAnimateValue, @@ -1514,21 +1516,22 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } } - private HighBrightnessModeController createHbmController() { - final DisplayDeviceConfig ddConfig = - mLogicalDisplay.getPrimaryDisplayDeviceLocked().getDisplayDeviceConfig(); + private HighBrightnessModeController createHbmControllerLocked() { + final DisplayDevice device = mLogicalDisplay.getPrimaryDisplayDeviceLocked(); + final DisplayDeviceConfig ddConfig = device.getDisplayDeviceConfig(); final IBinder displayToken = mLogicalDisplay.getPrimaryDisplayDeviceLocked().getDisplayTokenLocked(); final DisplayDeviceConfig.HighBrightnessModeData hbmData = ddConfig != null ? ddConfig.getHighBrightnessModeData() : null; - return new HighBrightnessModeController(mHandler, displayToken, PowerManager.BRIGHTNESS_MIN, - PowerManager.BRIGHTNESS_MAX, hbmData, + final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked(); + return new HighBrightnessModeController(mHandler, info.width, info.height, displayToken, + PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX, hbmData, () -> { sendUpdatePowerStateLocked(); mHandler.post(mOnBrightnessChangeRunnable); // TODO(b/192258832): Switch the HBMChangeCallback to a listener pattern. mAutomaticBrightnessController.update(); - }, mContext); + }, mContext, mBrightnessSetting); } private void blockScreenOn() { @@ -1680,11 +1683,10 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mHbmController.getCurrentBrightnessMin(), mHbmController.getCurrentBrightnessMax()); } - // Checks whether the brightness is within the valid brightness range, not including the off or - // invalid states. - private boolean isValidBrightnessValue(float brightnessState) { - return brightnessState >= PowerManager.BRIGHTNESS_MIN - && brightnessState <= PowerManager.BRIGHTNESS_MAX; + // Checks whether the brightness is within the valid brightness range, not including off. + private boolean isValidBrightnessValue(float brightness) { + return brightness >= PowerManager.BRIGHTNESS_MIN + && brightness <= PowerManager.BRIGHTNESS_MAX; } private void animateScreenBrightness(float target, float sdrTarget, float rate) { @@ -2014,6 +2016,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } private void putScreenBrightnessSetting(float brightnessValue, boolean updateCurrent) { + if (!isValidBrightnessValue(brightnessValue)) { + return; + } if (updateCurrent) { setCurrentScreenBrightness(brightnessValue); } @@ -2060,8 +2065,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call || mPendingScreenBrightnessSetting < 0.0f)) { return brightnessSplineChanged; } - if (BrightnessSynchronizer.floatEquals( - mCurrentScreenBrightnessSetting, mPendingScreenBrightnessSetting)) { + if (mCurrentScreenBrightnessSetting == mPendingScreenBrightnessSetting) { mPendingScreenBrightnessSetting = PowerManager.BRIGHTNESS_INVALID_FLOAT; mTemporaryScreenBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT; return brightnessSplineChanged; diff --git a/services/core/java/com/android/server/display/DisplayPowerState.java b/services/core/java/com/android/server/display/DisplayPowerState.java index b58dd38348aa..6af192371e3d 100644 --- a/services/core/java/com/android/server/display/DisplayPowerState.java +++ b/services/core/java/com/android/server/display/DisplayPowerState.java @@ -26,8 +26,6 @@ import android.util.Slog; import android.view.Choreographer; import android.view.Display; -import com.android.internal.display.BrightnessSynchronizer; - import java.io.PrintWriter; /** @@ -166,10 +164,11 @@ final class DisplayPowerState { /** * Sets the display's SDR brightness. * - * @param brightness The brightness, ranges from 0.0f (minimum / off) to 1.0f (brightest). + * @param brightness The brightness, ranges from 0.0f (minimum) to 1.0f (brightest), or is -1f + * (off). */ public void setSdrScreenBrightness(float brightness) { - if (!BrightnessSynchronizer.floatEquals(mSdrScreenBrightness, brightness)) { + if (mSdrScreenBrightness != brightness) { if (DEBUG) { Slog.d(TAG, "setSdrScreenBrightness: brightness=" + brightness); } @@ -192,10 +191,11 @@ final class DisplayPowerState { /** * Sets the display brightness. * - * @param brightness The brightness, ranges from 0.0f (minimum / off) to 1.0f (brightest). + * @param brightness The brightness, ranges from 0.0f (minimum) to 1.0f (brightest), or is -1f + * (off). */ public void setScreenBrightness(float brightness) { - if (!BrightnessSynchronizer.floatEquals(mScreenBrightness, brightness)) { + if (mScreenBrightness != brightness) { if (DEBUG) { Slog.d(TAG, "setScreenBrightness: brightness=" + brightness); } @@ -432,10 +432,8 @@ final class DisplayPowerState { public boolean setState(int state, float brightnessState, float sdrBrightnessState) { synchronized (mLock) { boolean stateChanged = state != mPendingState; - boolean backlightChanged = - !BrightnessSynchronizer.floatEquals(brightnessState, mPendingBacklight) - || !BrightnessSynchronizer.floatEquals( - sdrBrightnessState, mPendingSdrBacklight); + boolean backlightChanged = brightnessState != mPendingBacklight + || sdrBrightnessState != mPendingSdrBacklight; if (stateChanged || backlightChanged) { if (DEBUG) { Slog.d(TAG, "Requesting new screen state: state=" @@ -486,10 +484,8 @@ final class DisplayPowerState { stateChanged = (state != mActualState); brightnessState = mPendingBacklight; sdrBrightnessState = mPendingSdrBacklight; - backlightChanged = - !BrightnessSynchronizer.floatEquals(brightnessState, mActualBacklight) - || !BrightnessSynchronizer.floatEquals( - sdrBrightnessState, mActualSdrBacklight); + backlightChanged = brightnessState != mActualBacklight + || sdrBrightnessState != mActualSdrBacklight; if (!stateChanged) { // State changed applied, notify outer class. postScreenUpdateThreadSafe(); diff --git a/services/core/java/com/android/server/display/HighBrightnessModeController.java b/services/core/java/com/android/server/display/HighBrightnessModeController.java index d6294223556d..e0b4d47de0ee 100644 --- a/services/core/java/com/android/server/display/HighBrightnessModeController.java +++ b/services/core/java/com/android/server/display/HighBrightnessModeController.java @@ -31,11 +31,13 @@ import android.os.SystemClock; import android.os.Temperature; import android.os.UserHandle; import android.provider.Settings; +import android.util.MathUtils; import android.util.Slog; import android.util.TimeUtils; import android.view.SurfaceControlHdrLayerInfoListener; import com.android.internal.annotations.VisibleForTesting; +import com.android.server.display.BrightnessSetting.BrightnessSettingListener; import com.android.server.display.DisplayDeviceConfig.HighBrightnessModeData; import com.android.server.display.DisplayManagerService.Clock; @@ -56,6 +58,8 @@ class HighBrightnessModeController { private static final boolean DEBUG = false; + private static final float HDR_PERCENT_OF_SCREEN_REQUIRED = 0.50f; + private final float mBrightnessMin; private final float mBrightnessMax; private final Handler mHandler; @@ -66,6 +70,7 @@ class HighBrightnessModeController { private final Context mContext; private final SettingsObserver mSettingsObserver; private final Injector mInjector; + private final BrightnessSettingListener mBrightnessSettingListener = this::onBrightnessChanged; private SurfaceControlHdrLayerInfoListener mHdrListener; private HighBrightnessModeData mHbmData; @@ -74,11 +79,15 @@ class HighBrightnessModeController { private boolean mIsInAllowedAmbientRange = false; private boolean mIsTimeAvailable = false; private boolean mIsAutoBrightnessEnabled = false; - private float mAutoBrightness; + private float mBrightness; private int mHbmMode = BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF; private boolean mIsHdrLayerPresent = false; private boolean mIsThermalStatusWithinLimit = true; private boolean mIsBlockedByLowPowerMode = false; + private int mWidth; + private int mHeight; + private BrightnessSetting mBrightnessSetting; + private float mAmbientLux; /** * If HBM is currently running, this is the start time for the current HBM session. @@ -92,30 +101,32 @@ class HighBrightnessModeController { */ private LinkedList<HbmEvent> mEvents = new LinkedList<>(); - HighBrightnessModeController(Handler handler, IBinder displayToken, float brightnessMin, - float brightnessMax, HighBrightnessModeData hbmData, Runnable hbmChangeCallback, - Context context) { - this(new Injector(), handler, displayToken, brightnessMin, brightnessMax, - hbmData, hbmChangeCallback, context); + HighBrightnessModeController(Handler handler, int width, int height, IBinder displayToken, + float brightnessMin, float brightnessMax, HighBrightnessModeData hbmData, + Runnable hbmChangeCallback, Context context, BrightnessSetting brightnessSetting) { + this(new Injector(), handler, width, height, displayToken, brightnessMin, brightnessMax, + hbmData, hbmChangeCallback, context, brightnessSetting); } @VisibleForTesting - HighBrightnessModeController(Injector injector, Handler handler, IBinder displayToken, - float brightnessMin, float brightnessMax, HighBrightnessModeData hbmData, - Runnable hbmChangeCallback, Context context) { + HighBrightnessModeController(Injector injector, Handler handler, int width, int height, + IBinder displayToken, float brightnessMin, float brightnessMax, + HighBrightnessModeData hbmData, Runnable hbmChangeCallback, + Context context, BrightnessSetting brightnessSetting) { mInjector = injector; + mContext = context; mClock = injector.getClock(); mHandler = handler; mBrightnessMin = brightnessMin; mBrightnessMax = brightnessMax; + mBrightness = brightnessSetting.getBrightness(); mHbmChangeCallback = hbmChangeCallback; - mContext = context; - mAutoBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT; - mRecalcRunnable = this::recalculateTimeAllowance; - mHdrListener = new HdrListener(); mSkinThermalStatusObserver = new SkinThermalStatusObserver(mInjector, mHandler); mSettingsObserver = new SettingsObserver(mHandler); - resetHbmData(displayToken, hbmData); + mRecalcRunnable = this::recalculateTimeAllowance; + mHdrListener = new HdrListener(); + + resetHbmData(width, height, displayToken, hbmData, brightnessSetting); } void setAutoBrightnessEnabled(boolean isEnabled) { @@ -123,7 +134,7 @@ class HighBrightnessModeController { return; } if (DEBUG) { - Slog.d(TAG, "setAutoBrightness( " + isEnabled + " )"); + Slog.d(TAG, "setAutoBrightnessEnabled( " + isEnabled + " )"); } mIsAutoBrightnessEnabled = isEnabled; mIsInAllowedAmbientRange = false; // reset when auto-brightness switches @@ -147,11 +158,22 @@ class HighBrightnessModeController { } } + float getNormalBrightnessMax() { + return deviceSupportsHbm() ? mHbmData.transitionPoint : mBrightnessMax; + } + float getHdrBrightnessValue() { - return mBrightnessMax; + // For HDR brightness, we take the current brightness and scale it to the max. The reason + // we do this is because we want brightness to go to HBM max when it would normally go + // to normal max, meaning it should not wait to go to 10000 lux (or whatever the transition + // point happens to be) in order to go full HDR. Likewise, HDR on manual brightness should + // automatically scale the brightness without forcing the user to adjust to higher values. + return MathUtils.map(getCurrentBrightnessMin(), getCurrentBrightnessMax(), + mBrightnessMin, mBrightnessMax, mBrightness); } void onAmbientLuxChange(float ambientLux) { + mAmbientLux = ambientLux; if (!deviceSupportsHbm() || !mIsAutoBrightnessEnabled) { return; } @@ -163,17 +185,17 @@ class HighBrightnessModeController { } } - void onAutoBrightnessChanged(float autoBrightness) { + @VisibleForTesting + void onBrightnessChanged(float brightness) { if (!deviceSupportsHbm()) { return; } - final float oldAutoBrightness = mAutoBrightness; - mAutoBrightness = autoBrightness; + mBrightness = brightness; // If we are starting or ending a high brightness mode session, store the current // session in mRunningStartTimeMillis, or the old one in mEvents. final boolean wasHbmDrainingAvailableTime = mRunningStartTimeMillis != -1; - final boolean shouldHbmDrainAvailableTime = mAutoBrightness > mHbmData.transitionPoint + final boolean shouldHbmDrainAvailableTime = mBrightness > mHbmData.transitionPoint && !mIsHdrLayerPresent; if (wasHbmDrainingAvailableTime != shouldHbmDrainAvailableTime) { final long currentTime = mClock.uptimeMillis(); @@ -202,8 +224,12 @@ class HighBrightnessModeController { mSettingsObserver.stopObserving(); } - void resetHbmData(IBinder displayToken, HighBrightnessModeData hbmData) { + void resetHbmData(int width, int height, IBinder displayToken, HighBrightnessModeData hbmData, + BrightnessSetting brightnessSetting) { + mWidth = width; + mHeight = height; mHbmData = hbmData; + resetBrightnessSetting(brightnessSetting); unregisterHdrListener(); mSkinThermalStatusObserver.stopObserving(); mSettingsObserver.stopObserving(); @@ -227,21 +253,23 @@ class HighBrightnessModeController { private void dumpLocal(PrintWriter pw) { pw.println("HighBrightnessModeController:"); + pw.println(" mBrightness=" + mBrightness); pw.println(" mCurrentMin=" + getCurrentBrightnessMin()); pw.println(" mCurrentMax=" + getCurrentBrightnessMax()); pw.println(" mHbmMode=" + BrightnessInfo.hbmToString(mHbmMode)); - pw.println(" remainingTime=" + calculateRemainingTime(mClock.uptimeMillis())); pw.println(" mHbmData=" + mHbmData); + pw.println(" mAmbientLux=" + mAmbientLux); pw.println(" mIsInAllowedAmbientRange=" + mIsInAllowedAmbientRange); - pw.println(" mIsTimeAvailable= " + mIsTimeAvailable); pw.println(" mIsAutoBrightnessEnabled=" + mIsAutoBrightnessEnabled); - pw.println(" mAutoBrightness=" + mAutoBrightness); pw.println(" mIsHdrLayerPresent=" + mIsHdrLayerPresent); pw.println(" mBrightnessMin=" + mBrightnessMin); pw.println(" mBrightnessMax=" + mBrightnessMax); + pw.println(" remainingTime=" + calculateRemainingTime(mClock.uptimeMillis())); + pw.println(" mIsTimeAvailable= " + mIsTimeAvailable); pw.println(" mRunningStartTimeMillis=" + TimeUtils.formatUptime(mRunningStartTimeMillis)); pw.println(" mIsThermalStatusWithinLimit=" + mIsThermalStatusWithinLimit); pw.println(" mIsBlockedByLowPowerMode=" + mIsBlockedByLowPowerMode); + pw.println(" width*height=" + mWidth + "*" + mHeight); pw.println(" mEvents="); final long currentTime = mClock.uptimeMillis(); long lastStartTime = currentTime; @@ -268,9 +296,26 @@ class HighBrightnessModeController { return event.startTimeMillis; } + private void resetBrightnessSetting(BrightnessSetting brightnessSetting) { + if (mBrightnessSetting != null) { + mBrightnessSetting.unregisterListener(mBrightnessSettingListener); + } + mBrightnessSetting = brightnessSetting; + if (mBrightnessSetting != null) { + mBrightnessSetting.registerListener(mBrightnessSettingListener); + } + } + private boolean isCurrentlyAllowed() { - return mIsHdrLayerPresent - || (mIsAutoBrightnessEnabled && mIsTimeAvailable && mIsInAllowedAmbientRange + // Returns true if HBM is allowed (above the ambient lux threshold) and there's still + // time within the current window for additional HBM usage. We return false if there is an + // HDR layer because we don't want the brightness MAX to change for HDR, which has its + // brightness scaled in a different way than sunlight HBM that doesn't require changing + // the MAX. HDR also needs to work under manual brightness which never adjusts the + // brightness maximum; so we implement HDR-HBM in a way that doesn't adjust the max. + // See {@link #getHdrBrightnessValue}. + return !mIsHdrLayerPresent + && (mIsAutoBrightnessEnabled && mIsTimeAvailable && mIsInAllowedAmbientRange && mIsThermalStatusWithinLimit && !mIsBlockedByLowPowerMode); } @@ -334,13 +379,13 @@ class HighBrightnessModeController { // or if brightness is already in the high range, if there is any time left at all. final boolean isAllowedWithoutRestrictions = remainingTime >= mHbmData.timeMinMillis; final boolean isOnlyAllowedToStayOn = !isAllowedWithoutRestrictions - && remainingTime > 0 && mAutoBrightness > mHbmData.transitionPoint; + && remainingTime > 0 && mBrightness > mHbmData.transitionPoint; mIsTimeAvailable = isAllowedWithoutRestrictions || isOnlyAllowedToStayOn; // Calculate the time at which we want to recalculate mIsTimeAvailable in case a lux or // brightness change doesn't happen before then. long nextTimeout = -1; - if (mAutoBrightness > mHbmData.transitionPoint) { + if (mBrightness > mHbmData.transitionPoint) { // if we're in high-lux now, timeout when we run out of allowed time. nextTimeout = currentTime + remainingTime; } else if (!mIsTimeAvailable && mEvents.size() > 0) { @@ -370,7 +415,7 @@ class HighBrightnessModeController { + ", mIsInAllowedAmbientRange: " + mIsInAllowedAmbientRange + ", mIsThermalStatusWithinLimit: " + mIsThermalStatusWithinLimit + ", mIsBlockedByLowPowerMode: " + mIsBlockedByLowPowerMode - + ", brightness: " + mAutoBrightness + + ", mBrightness: " + mBrightness + ", RunningStartTimeMillis: " + mRunningStartTimeMillis + ", nextTimeout: " + (nextTimeout != -1 ? (nextTimeout - currentTime) : -1) + ", events: " + mEvents); @@ -447,11 +492,12 @@ class HighBrightnessModeController { public void onHdrInfoChanged(IBinder displayToken, int numberOfHdrLayers, int maxW, int maxH, int flags) { mHandler.post(() -> { - mIsHdrLayerPresent = numberOfHdrLayers > 0; - // Calling the auto-brightness update so that we can recalculate - // auto-brightness with HDR in mind. When HDR layers are present, - // we don't limit auto-brightness' HBM time limits. - onAutoBrightnessChanged(mAutoBrightness); + mIsHdrLayerPresent = numberOfHdrLayers > 0 + && (float) (maxW * maxH) + >= ((float) (mWidth * mHeight) * HDR_PERCENT_OF_SCREEN_REQUIRED); + // Calling the brightness update so that we can recalculate + // brightness with HDR in mind. + onBrightnessChanged(mBrightness); }); } } diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java index 2f17481f7487..f953cc8c8a27 100644 --- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java +++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java @@ -648,12 +648,11 @@ final class LocalDisplayAdapter extends DisplayAdapter { public Runnable requestDisplayStateLocked(final int state, final float brightnessState, final float sdrBrightnessState) { // Assume that the brightness is off if the display is being turned off. - assert state != Display.STATE_OFF || BrightnessSynchronizer.floatEquals( - brightnessState, PowerManager.BRIGHTNESS_OFF_FLOAT); + assert state != Display.STATE_OFF + || brightnessState == PowerManager.BRIGHTNESS_OFF_FLOAT; final boolean stateChanged = (mState != state); - final boolean brightnessChanged = - !(BrightnessSynchronizer.floatEquals(mBrightnessState, brightnessState) - && BrightnessSynchronizer.floatEquals(mSdrBrightnessState, sdrBrightnessState)); + final boolean brightnessChanged = mBrightnessState != brightnessState + || mSdrBrightnessState != sdrBrightnessState; if (stateChanged || brightnessChanged) { final long physicalDisplayId = mPhysicalDisplayId; final IBinder token = getDisplayTokenLocked(); @@ -807,8 +806,7 @@ final class LocalDisplayAdapter extends DisplayAdapter { } private float brightnessToBacklight(float brightness) { - if (BrightnessSynchronizer.floatEquals( - brightness, PowerManager.BRIGHTNESS_OFF_FLOAT)) { + if (brightness == PowerManager.BRIGHTNESS_OFF_FLOAT) { return PowerManager.BRIGHTNESS_OFF_FLOAT; } else { return getDisplayDeviceConfig().getBacklightFromBrightness(brightness); diff --git a/services/core/java/com/android/server/display/RampAnimator.java b/services/core/java/com/android/server/display/RampAnimator.java index 20feafa2d19c..ed3b15fb2661 100644 --- a/services/core/java/com/android/server/display/RampAnimator.java +++ b/services/core/java/com/android/server/display/RampAnimator.java @@ -20,8 +20,6 @@ import android.animation.ValueAnimator; import android.util.FloatProperty; import android.view.Choreographer; -import com.android.internal.display.BrightnessSynchronizer; - /** * A custom animator that progressively updates a property value at * a given variable rate until it reaches a particular target value. @@ -157,10 +155,10 @@ class RampAnimator<T> { } final float oldCurrentValue = mCurrentValue; mCurrentValue = mAnimatedValue; - if (!BrightnessSynchronizer.floatEquals(oldCurrentValue, mCurrentValue)) { + if (oldCurrentValue != mCurrentValue) { mProperty.setValue(mObject, mCurrentValue); } - if (!BrightnessSynchronizer.floatEquals(mTargetValue, mCurrentValue)) { + if (mTargetValue != mCurrentValue) { postAnimationCallback(); } else { mAnimating = false; diff --git a/services/core/java/com/android/server/location/provider/LocationProviderManager.java b/services/core/java/com/android/server/location/provider/LocationProviderManager.java index 5c1ce6488444..8c9068daed9b 100644 --- a/services/core/java/com/android/server/location/provider/LocationProviderManager.java +++ b/services/core/java/com/android/server/location/provider/LocationProviderManager.java @@ -155,7 +155,7 @@ public class LocationProviderManager extends private static final float FASTEST_INTERVAL_JITTER_PERCENTAGE = .10f; // max absolute jitter allowed for min update interval evaluation - private static final int MAX_FASTEST_INTERVAL_JITTER_MS = 5 * 1000; + private static final int MAX_FASTEST_INTERVAL_JITTER_MS = 30 * 1000; // minimum amount of request delay in order to respect the delay, below this value the request // will just be scheduled immediately diff --git a/services/core/java/com/android/server/media/metrics/MediaMetricsManagerService.java b/services/core/java/com/android/server/media/metrics/MediaMetricsManagerService.java index 981e75988d56..2519bbf389ba 100644 --- a/services/core/java/com/android/server/media/metrics/MediaMetricsManagerService.java +++ b/services/core/java/com/android/server/media/metrics/MediaMetricsManagerService.java @@ -195,7 +195,7 @@ public final class MediaMetricsManagerService extends SystemService { } private String getSessionIdInternal(int userId) { - byte[] byteId = new byte[16]; // 128 bits + byte[] byteId = new byte[12]; // 96 bits (128 bits when expanded to Base64 string) mSecureRandom.nextBytes(byteId); String id = Base64.encodeToString( byteId, Base64.NO_PADDING | Base64.NO_WRAP | Base64.URL_SAFE); diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java index a3daae4d854b..bccc52fe350a 100644 --- a/services/core/java/com/android/server/notification/ManagedServices.java +++ b/services/core/java/com/android/server/notification/ManagedServices.java @@ -570,10 +570,12 @@ abstract public class ManagedServices { protected final void migrateToXml() { for (UserInfo user : mUm.getUsers()) { final ContentResolver cr = mContext.getContentResolver(); - addApprovedList(Settings.Secure.getStringForUser( - cr, - getConfig().secureSettingName, - user.id), user.id, true); + if (!TextUtils.isEmpty(getConfig().secureSettingName)) { + addApprovedList(Settings.Secure.getStringForUser( + cr, + getConfig().secureSettingName, + user.id), user.id, true); + } if (!TextUtils.isEmpty(getConfig().secondarySettingName)) { addApprovedList(Settings.Secure.getStringForUser( cr, diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 1bd5e72bdb15..b54e8f973bd6 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -6194,8 +6194,10 @@ public class NotificationManagerService extends SystemService { // Fix the notification as best we can. try { fixNotification(notification, pkg, tag, id, userId); - } catch (Exception e) { + if (notification.isForegroundService()) { + throw new SecurityException("Invalid FGS notification", e); + } Slog.e(TAG, "Cannot fix notification", e); return; } @@ -6206,7 +6208,7 @@ public class NotificationManagerService extends SystemService { // FGS-related situation up front, outside of any locks so it's safe to call into // the Activity Manager. final ServiceNotificationPolicy policy = mAmi.applyForegroundServiceNotification( - notification, id, pkg, userId); + notification, tag, id, pkg, userId); if (policy == ServiceNotificationPolicy.UPDATE_ONLY) { // Proceed if the notification is already showing/known, otherwise ignore // because the service lifecycle logic has retained responsibility for its diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java index b144ff27c993..16a0b7e39a07 100644 --- a/services/core/java/com/android/server/notification/ZenModeHelper.java +++ b/services/core/java/com/android/server/notification/ZenModeHelper.java @@ -372,7 +372,7 @@ public class ZenModeHelper { } } if (rule.enabled != automaticZenRule.isEnabled()) { - dispatchOnAutomaticRuleStatusChanged(mConfig.user, rule.pkg, ruleId, + dispatchOnAutomaticRuleStatusChanged(mConfig.user, rule.getPkg(), ruleId, automaticZenRule.isEnabled() ? AUTOMATIC_RULE_STATUS_ENABLED : AUTOMATIC_RULE_STATUS_DISABLED); } @@ -391,13 +391,14 @@ public class ZenModeHelper { if (ruleToRemove == null) return false; if (canManageAutomaticZenRule(ruleToRemove)) { newConfig.automaticRules.remove(id); - if (ruleToRemove.pkg != null && !"android".equals(ruleToRemove.pkg)) { + if (ruleToRemove.getPkg() != null && !"android".equals(ruleToRemove.getPkg())) { for (ZenRule currRule : newConfig.automaticRules.values()) { - if (currRule.pkg != null && currRule.pkg.equals(ruleToRemove.pkg)) { + if (currRule.getPkg() != null + && currRule.getPkg().equals(ruleToRemove.getPkg())) { break; // no need to remove from cache } } - mRulesUidCache.remove(getPackageUserKey(ruleToRemove.pkg, newConfig.user)); + mRulesUidCache.remove(getPackageUserKey(ruleToRemove.getPkg(), newConfig.user)); } if (DEBUG) Log.d(TAG, "removeZenRule zenRule=" + id + " reason=" + reason); } else { @@ -405,7 +406,7 @@ public class ZenModeHelper { "Cannot delete rules not owned by your condition provider"); } dispatchOnAutomaticRuleStatusChanged( - mConfig.user, ruleToRemove.pkg, id, AUTOMATIC_RULE_STATUS_REMOVED); + mConfig.user, ruleToRemove.getPkg(), id, AUTOMATIC_RULE_STATUS_REMOVED); return setConfigLocked(newConfig, reason, null, true); } } @@ -417,14 +418,7 @@ public class ZenModeHelper { newConfig = mConfig.copy(); for (int i = newConfig.automaticRules.size() - 1; i >= 0; i--) { ZenRule rule = newConfig.automaticRules.get(newConfig.automaticRules.keyAt(i)); - String pkg = rule.pkg != null - ? rule.pkg - : (rule.component != null) - ? rule.component.getPackageName() - : (rule.configurationActivity != null) - ? rule.configurationActivity.getPackageName() - : null; - if (Objects.equals(pkg, packageName) && canManageAutomaticZenRule(rule)) { + if (Objects.equals(rule.getPkg(), packageName) && canManageAutomaticZenRule(rule)) { newConfig.automaticRules.removeAt(i); } } @@ -524,7 +518,7 @@ public class ZenModeHelper { if (packages != null) { final int packageCount = packages.length; for (int i = 0; i < packageCount; i++) { - if (packages[i].equals(rule.pkg)) { + if (packages[i].equals(rule.getPkg())) { return true; } } @@ -834,8 +828,8 @@ public class ZenModeHelper { ZenRule rule = newConfig.automaticRules.get(newConfig.automaticRules.keyAt(i)); if (RULE_INSTANCE_GRACE_PERIOD < (currentTime - rule.creationTime)) { try { - if (rule.pkg != null) { - mPm.getPackageInfo(rule.pkg, PackageManager.MATCH_ANY_USER); + if (rule.getPkg() != null) { + mPm.getPackageInfo(rule.getPkg(), PackageManager.MATCH_ANY_USER); } } catch (PackageManager.NameNotFoundException e) { newConfig.automaticRules.removeAt(i); @@ -1246,7 +1240,7 @@ public class ZenModeHelper { } // Look for packages and enablers, enablers get priority. - String pkg = rule.pkg == null ? "" : rule.pkg; + String pkg = rule.getPkg() == null ? "" : rule.getPkg(); if (rule.enabler != null) { pkg = rule.enabler; id = ZenModeConfig.MANUAL_RULE_ID; diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java index 73dc8dc78fbf..53bf7b8aa8ae 100644 --- a/services/core/java/com/android/server/pm/ApexManager.java +++ b/services/core/java/com/android/server/pm/ApexManager.java @@ -1051,13 +1051,18 @@ public abstract class ApexManager { final ParsedPackage parsedPackage2 = packageParser.parsePackage( new File(apexInfo.modulePath), flags, /* useCaches= */ false); final PackageInfo finalApexPkg = PackageInfoWithoutStateUtils.generate( - parsedPackage, apexInfo, flags); + parsedPackage2, apexInfo, flags); // Installation was successful, time to update mAllPackagesCache synchronized (mLock) { - for (int i = 0, size = mAllPackagesCache.size(); i < size; i++) { - if (mAllPackagesCache.get(i).equals(existingApexPkg)) { - mAllPackagesCache.set(i, finalApexPkg); - break; + if (isFactory(existingApexPkg)) { + existingApexPkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_INSTALLED; + mAllPackagesCache.add(finalApexPkg); + } else { + for (int i = 0, size = mAllPackagesCache.size(); i < size; i++) { + if (mAllPackagesCache.get(i).equals(existingApexPkg)) { + mAllPackagesCache.set(i, finalApexPkg); + break; + } } } } diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index acc83cfd05b6..6adde9ad25fd 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -957,7 +957,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { android.Manifest.permission.UPDATE_PACKAGES_WITHOUT_USER_ACTION, mInstallerUid) == PackageManager.PERMISSION_GRANTED); final int targetPackageUid = mPm.getPackageUid(packageName, 0, userId); - final boolean isUpdate = targetPackageUid != -1; + final boolean isUpdate = targetPackageUid != -1 || isApexSession(); final InstallSourceInfo existingInstallSourceInfo = isUpdate ? mPm.getInstallSourceInfo(packageName) : null; diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index faa37a03c971..04771b99c09f 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -112,8 +112,6 @@ import static com.android.internal.annotations.VisibleForTesting.Visibility; import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_MANAGED_PROFILE; import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_PARENT; import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME; -import static com.android.internal.util.ArrayUtils.emptyIfNull; -import static com.android.internal.util.ArrayUtils.filter; import static com.android.internal.util.FrameworkStatsLog.BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_DATA_APP_AVG_SCAN_TIME; import static com.android.internal.util.FrameworkStatsLog.BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_INIT_TIME; import static com.android.internal.util.FrameworkStatsLog.BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_SYSTEM_APP_AVG_SCAN_TIME; @@ -6179,6 +6177,9 @@ public class PackageManagerService extends IPackageManager.Stub } if (succeeded) { + // Clear the uid cache after we installed a new package. + mPerUidReadTimeoutsCache = null; + // Send the removed broadcasts if (res.removedInfo != null) { res.removedInfo.sendPackageRemovedBroadcasts(killApp, false /*removedBySystem*/); @@ -11608,9 +11609,17 @@ public class PackageManagerService extends IPackageManager.Stub return resolveContentProviderInternal(name, flags, userId); } + public ProviderInfo resolveContentProvider(String name, int flags, int userId, int callingUid) { + return resolveContentProviderInternal(name, flags, userId, callingUid); + } + private ProviderInfo resolveContentProviderInternal(String name, int flags, int userId) { + return resolveContentProviderInternal(name, flags, userId, Binder.getCallingUid()); + } + + private ProviderInfo resolveContentProviderInternal(String name, int flags, int userId, + int callingUid) { if (!mUserManager.exists(userId)) return null; - final int callingUid = Binder.getCallingUid(); flags = updateFlagsForComponent(flags, userId); final ProviderInfo providerInfo = mComponentResolver.queryProvider(name, flags, userId); boolean checkedGrants = false; @@ -17351,6 +17360,7 @@ public class PackageManagerService extends IPackageManager.Stub } catch (PackageManagerException e) { request.installResult.setError("APEX installation failed", e); } + invalidatePackageInfoCache(); notifyInstallObserver(request.installResult, request.args.observer); } @@ -23624,18 +23634,6 @@ public class PackageManagerService extends IPackageManager.Stub getPackageFromComponentString(R.string.config_defaultAppPredictionService)); } - private @NonNull String[] dropNonSystemPackages(@NonNull String[] pkgNames) { - return emptyIfNull(filter(pkgNames, String[]::new, mIsSystemPackage), String.class); - } - - private Predicate<String> mIsSystemPackage = (pkgName) -> { - if ("android".equals(pkgName)) { - return true; - } - AndroidPackage pkg = mPackages.get(pkgName); - return pkg != null && pkg.isSystem(); - }; - @Override public String getSystemCaptionsServicePackageName() { return ensureSystemPackageName( @@ -27259,7 +27257,7 @@ public class PackageManagerService extends IPackageManager.Stub @Override public @NonNull String[] getKnownPackageNames(int knownPackage, int userId) { - return dropNonSystemPackages(getKnownPackageNamesInternal(knownPackage, userId)); + return getKnownPackageNamesInternal(knownPackage, userId); } private String[] getKnownPackageNamesInternal(int knownPackage, int userId) { @@ -27778,6 +27776,13 @@ public class PackageManagerService extends IPackageManager.Stub } @Override + public ProviderInfo resolveContentProvider(String name, int flags, int userId, + int callingUid) { + return PackageManagerService.this.resolveContentProviderInternal( + name, flags, userId, callingUid); + } + + @Override public void addIsolatedUid(int isolatedUid, int ownerUid) { synchronized (mLock) { mIsolatedOwners.put(isolatedUid, ownerUid); diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java index 81ea46514d3d..376326264d9c 100644 --- a/services/core/java/com/android/server/pm/PackageSetting.java +++ b/services/core/java/com/android/server/pm/PackageSetting.java @@ -31,6 +31,7 @@ import com.android.server.pm.parsing.pkg.AndroidPackage; import com.android.server.pm.permission.LegacyPermissionDataProvider; import com.android.server.pm.permission.LegacyPermissionState; import com.android.server.pm.pkg.PackageStateUnserialized; +import com.android.server.utils.SnapshotCache; import java.io.File; import java.util.ArrayList; @@ -81,6 +82,7 @@ public class PackageSetting extends PackageSettingBase { * object equality to check whether shared user settings are the same. */ SharedUserSetting sharedUser; + /** * Temporary holding space for the shared user ID. While parsing package settings, the * shared users tag may come after the packages. In this case, we must delay linking the @@ -103,6 +105,19 @@ public class PackageSetting extends PackageSettingBase { @NonNull private UUID mDomainSetId; + /** + * Snapshot support. + */ + private final SnapshotCache<PackageSetting> mSnapshot; + + private SnapshotCache<PackageSetting> makeCache() { + return new SnapshotCache<PackageSetting>(this, this) { + @Override + public PackageSetting createSnapshot() { + return new PackageSetting(mSource, true); + }}; + } + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) public PackageSetting(String name, String realName, @NonNull File codePath, String legacyNativeLibraryPathString, String primaryCpuAbiString, @@ -118,6 +133,7 @@ public class PackageSetting extends PackageSettingBase { this.sharedUserId = sharedUserId; mDomainSetId = domainSetId; copyMimeGroups(mimeGroups); + mSnapshot = makeCache(); } /** @@ -127,6 +143,7 @@ public class PackageSetting extends PackageSettingBase { PackageSetting(PackageSetting orig) { super(orig, orig.realName); doCopy(orig); + mSnapshot = makeCache(); } /** @@ -137,6 +154,33 @@ public class PackageSetting extends PackageSettingBase { PackageSetting(PackageSetting orig, String realPkgName) { super(orig, realPkgName); doCopy(orig); + mSnapshot = makeCache(); + } + + /** + * Create a snapshot. The copy constructor is already in use and cannot be modified + * for this purpose. + */ + PackageSetting(PackageSetting orig, boolean snapshot) { + super(orig, snapshot); + // The existing doCopy() method cannot be used in here because sharedUser must be + // a snapshot, and not a reference. Also, the pkgState must be copied. However, + // this code should otherwise be kept in sync with doCopy(). + appId = orig.appId; + pkg = orig.pkg; + sharedUser = orig.sharedUser == null ? null : orig.sharedUser.snapshot(); + sharedUserId = orig.sharedUserId; + copyMimeGroups(orig.mimeGroups); + pkgState = orig.pkgState; + mDomainSetId = orig.getDomainSetId(); + mSnapshot = new SnapshotCache.Sealed(); + } + + /** + * Return the package snapshot. + */ + public PackageSetting snapshot() { + return mSnapshot.snapshot(); } /** @see #pkg **/ diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java index 731d41c38f79..bf82bd8b09d5 100644 --- a/services/core/java/com/android/server/pm/PackageSettingBase.java +++ b/services/core/java/com/android/server/pm/PackageSettingBase.java @@ -169,6 +169,15 @@ public abstract class PackageSettingBase extends SettingBase { doCopy(base); } + // A copy constructor used to create snapshots. The boolean is present only to + // match up with the constructor in PackageSetting. + PackageSettingBase(PackageSettingBase orig, boolean snapshot) { + super(orig); + name = orig.name; + realName = orig.realName; + doCopy(orig); + } + public void setInstallerPackageName(String packageName) { installSource = installSource.setInstallerPackage(packageName); onChanged(); diff --git a/services/core/java/com/android/server/pm/SettingBase.java b/services/core/java/com/android/server/pm/SettingBase.java index 0e8a278f3b6b..7b5c7e3a0c84 100644 --- a/services/core/java/com/android/server/pm/SettingBase.java +++ b/services/core/java/com/android/server/pm/SettingBase.java @@ -22,12 +22,13 @@ import android.content.pm.ApplicationInfo; import com.android.internal.annotations.VisibleForTesting; import com.android.server.pm.permission.LegacyPermissionState; +import com.android.server.utils.Snappable; import com.android.server.utils.Watchable; import com.android.server.utils.WatchableImpl; import com.android.server.utils.Watcher; @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) -public abstract class SettingBase implements Watchable { +public abstract class SettingBase implements Watchable, Snappable { // TODO: make this variable protected, or even private with a getter and setter. // Simply making it protected or private requires that the name be changed to conformm // to the Android naming convention, and that touches quite a few files. diff --git a/services/core/java/com/android/server/pm/SharedUserSetting.java b/services/core/java/com/android/server/pm/SharedUserSetting.java index 9b1c08d9c321..8ddbe08e2572 100644 --- a/services/core/java/com/android/server/pm/SharedUserSetting.java +++ b/services/core/java/com/android/server/pm/SharedUserSetting.java @@ -26,6 +26,7 @@ import android.util.proto.ProtoOutputStream; import com.android.internal.util.ArrayUtils; import com.android.server.pm.parsing.pkg.AndroidPackage; +import com.android.server.utils.SnapshotCache; import libcore.util.EmptyArray; @@ -49,12 +50,25 @@ public final class SharedUserSetting extends SettingBase { // that all apps within the sharedUser run in the same selinux context. int seInfoTargetSdkVersion; - final ArraySet<PackageSetting> packages = new ArraySet<>(); + final ArraySet<PackageSetting> packages; final PackageSignatures signatures = new PackageSignatures(); Boolean signaturesChanged; - ArrayMap<String, ParsedProcess> processes; + final ArrayMap<String, ParsedProcess> processes; + + /** + * Snapshot support. + */ + private final SnapshotCache<SharedUserSetting> mSnapshot; + + private SnapshotCache<SharedUserSetting> makeCache() { + return new SnapshotCache<SharedUserSetting>(this, this) { + @Override + public SharedUserSetting createSnapshot() { + return new SharedUserSetting(mSource); + }}; + } SharedUserSetting(String _name, int _pkgFlags, int _pkgPrivateFlags) { super(_pkgFlags, _pkgPrivateFlags); @@ -62,6 +76,31 @@ public final class SharedUserSetting extends SettingBase { uidPrivateFlags = _pkgPrivateFlags; name = _name; seInfoTargetSdkVersion = android.os.Build.VERSION_CODES.CUR_DEVELOPMENT; + packages = new ArraySet<>(); + processes = new ArrayMap<>(); + mSnapshot = makeCache(); + } + + // The copy constructor is used to create a snapshot + private SharedUserSetting(SharedUserSetting orig) { + super(orig); + name = orig.name; + uidFlags = orig.uidFlags; + uidPrivateFlags = orig.uidPrivateFlags; + packages = new ArraySet(orig.packages); + // A PackageParser.SigningDetails seems to consist solely of final attributes, so + // it is safe to copy the reference. + signatures.mSigningDetails = orig.signatures.mSigningDetails; + signaturesChanged = orig.signaturesChanged; + processes = new ArrayMap(orig.processes); + mSnapshot = new SnapshotCache.Sealed(); + } + + /** + * Return a read-only snapshot of this object. + */ + public SharedUserSetting snapshot() { + return mSnapshot.snapshot(); } @Override @@ -80,9 +119,6 @@ public final class SharedUserSetting extends SettingBase { void addProcesses(Map<String, ParsedProcess> newProcs) { if (newProcs != null) { final int numProcs = newProcs.size(); - if (processes == null) { - processes = new ArrayMap<>(numProcs); - } for (String key : newProcs.keySet()) { ParsedProcess newProc = newProcs.get(key); ParsedProcess proc = processes.get(newProc.getName()); @@ -191,7 +227,7 @@ public final class SharedUserSetting extends SettingBase { * Update tracked data about processes based on all known packages in the shared user ID. */ public void updateProcesses() { - processes = null; + processes.clear(); for (int i = packages.size() - 1; i >= 0; i--) { final AndroidPackage pkg = packages.valueAt(i).pkg; if (pkg != null) { @@ -230,14 +266,15 @@ public final class SharedUserSetting extends SettingBase { this.signaturesChanged = sharedUser.signaturesChanged; if (sharedUser.processes != null) { final int numProcs = sharedUser.processes.size(); - this.processes = new ArrayMap<>(numProcs); + this.processes.clear(); + this.processes.ensureCapacity(numProcs); for (int i = 0; i < numProcs; i++) { ParsedProcess proc = new ParsedProcess(sharedUser.processes.valueAt(i)); this.processes.put(proc.getName(), proc); } } else { - this.processes = null; + this.processes.clear(); } onChanged(); return this; 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 30ddbb60080f..97ccfe6e7b2c 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -2920,7 +2920,9 @@ public class PermissionManagerService extends IPermissionManager.Stub { wasChanged = true; } - if ((flags & FLAG_PERMISSION_REVOKED_COMPAT) != 0) { + if ((flags & FLAG_PERMISSION_REVOKED_COMPAT) != 0 + && !isPermissionSplitFromNonRuntime(permName, + pkg.getTargetSdkVersion())) { flags &= ~FLAG_PERMISSION_REVOKED_COMPAT; wasChanged = true; // Hard restricted permissions cannot be held. diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index e6adeb3abab8..fb4d96e305fc 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -904,7 +904,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } else { // handled by single key or another power key policy. - mSingleKeyGestureDetector.reset(); + if (!mSingleKeyGestureDetector.isKeyIntercepted(KEYCODE_POWER)) { + mSingleKeyGestureDetector.reset(); + } } finishPowerKeyPress(); @@ -918,7 +920,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { } private void powerPress(long eventTime, int count, boolean beganFromNonInteractive) { - mCameraGestureTriggered = false; if (mDefaultDisplayPolicy.isScreenOnEarly() && !mDefaultDisplayPolicy.isScreenOnFully()) { Slog.i(TAG, "Suppressed redundant power key press while " + "already in the process of turning the screen on."); @@ -1068,24 +1069,18 @@ public class PhoneWindowManager implements WindowManagerPolicy { } private int getMaxMultiPressPowerCount() { - // GestureLauncherService could handle power multi tap gesture. - if (mGestureLauncherService != null - && mGestureLauncherService.isEmergencyGestureEnabled()) { - return 5; // EMERGENCY_GESTURE_POWER_TAP_COUNT_THRESHOLD - } - + // The actual max power button press count is 5 + // (EMERGENCY_GESTURE_POWER_TAP_COUNT_THRESHOLD), which is coming from + // GestureLauncherService. + // To speed up the handling of single-press of power button inside SingleKeyGestureDetector, + // however, we limit the max count to the number of button presses actually handled by the + // SingleKeyGestureDetector. if (mTriplePressOnPowerBehavior != MULTI_PRESS_POWER_NOTHING) { return 3; } if (mDoublePressOnPowerBehavior != MULTI_PRESS_POWER_NOTHING) { return 2; } - - if (mGestureLauncherService != null - && mGestureLauncherService.isCameraDoubleTapPowerEnabled()) { - return 2; // CAMERA_POWER_TAP_COUNT_THRESHOLD - } - return 1; } @@ -1972,7 +1967,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { void onPress(long downTime) { powerPress(downTime, 1 /*count*/, mSingleKeyGestureDetector.beganFromNonInteractive()); - finishPowerKeyPress(); } @Override @@ -1995,7 +1989,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { @Override void onMultiPress(long downTime, int count) { powerPress(downTime, count, mSingleKeyGestureDetector.beganFromNonInteractive()); - finishPowerKeyPress(); } } @@ -3849,17 +3842,17 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (mGestureLauncherService == null) { return false; } - + mCameraGestureTriggered = false; final MutableBoolean outLaunched = new MutableBoolean(false); - final boolean gesturedServiceIntercepted = mGestureLauncherService.interceptPowerKeyDown( - event, interactive, outLaunched); - if (outLaunched.value) { - mCameraGestureTriggered = true; + mGestureLauncherService.interceptPowerKeyDown(event, interactive, outLaunched); + if (!outLaunched.value) { + return false; } - if (outLaunched.value && mRequestedOrSleepingDefaultDisplay) { + mCameraGestureTriggered = true; + if (mRequestedOrSleepingDefaultDisplay) { mCameraGestureTriggeredDuringGoingToSleep = true; } - return gesturedServiceIntercepted; + return true; } /** @@ -4232,7 +4225,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { mDefaultDisplayRotation.updateOrientationListener(); if (mKeyguardDelegate != null) { - mKeyguardDelegate.onFinishedGoingToSleep(pmSleepReason, mCameraGestureTriggered); + mKeyguardDelegate.onFinishedGoingToSleep(pmSleepReason, + mCameraGestureTriggeredDuringGoingToSleep); } if (mDisplayFoldController != null) { mDisplayFoldController.finishedGoingToSleep(); @@ -4428,6 +4422,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { // Called on the DisplayManager's DisplayPowerController thread. @Override public void screenTurnedOn(int displayId) { + if (DEBUG_WAKEUP) Slog.i(TAG, "Display " + displayId + " turned on..."); + if (displayId != DEFAULT_DISPLAY) { return; } diff --git a/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java b/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java index 3f4d920754ce..1ef2bf9151e0 100644 --- a/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java +++ b/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java @@ -272,8 +272,10 @@ public final class SingleKeyGestureDetector { if (DEBUG) { Log.i(TAG, "press key " + KeyEvent.keyCodeToString(event.getKeyCode())); } - mActiveRule.onPress(downTime); - reset(); + Message msg = mHandler.obtainMessage(MSG_KEY_DELAYED_PRESS, mActiveRule.mKeyCode, + 1, downTime); + msg.setAsynchronous(true); + mHandler.sendMessage(msg); return true; } @@ -316,10 +318,7 @@ public final class SingleKeyGestureDetector { } boolean isKeyIntercepted(int keyCode) { - if (mActiveRule != null && mActiveRule.shouldInterceptKey(keyCode)) { - return mHandledByLongPress; - } - return false; + return mActiveRule != null && mActiveRule.shouldInterceptKey(keyCode); } boolean beganFromNonInteractive() { diff --git a/services/core/java/com/android/server/speech/RemoteSpeechRecognitionService.java b/services/core/java/com/android/server/speech/RemoteSpeechRecognitionService.java index 9c8ff685d14d..068626588745 100644 --- a/services/core/java/com/android/server/speech/RemoteSpeechRecognitionService.java +++ b/services/core/java/com/android/server/speech/RemoteSpeechRecognitionService.java @@ -125,10 +125,12 @@ final class RemoteSpeechRecognitionService extends ServiceConnector.Impl<IRecogn } }); + // Eager local evaluation to avoid reading a different or null value at closure-run-time + final DelegatingListener listenerToStart = this.mDelegatingListener; run(service -> service.startListening( recognizerIntent, - mDelegatingListener, + listenerToStart, attributionSource)); } } @@ -162,7 +164,9 @@ final class RemoteSpeechRecognitionService extends ServiceConnector.Impl<IRecogn } mRecordingInProgress = false; - run(service -> service.stopListening(mDelegatingListener)); + // Eager local evaluation to avoid reading a different or null value at closure-run-time + final DelegatingListener listenerToStop = this.mDelegatingListener; + run(service -> service.stopListening(listenerToStop)); } } 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 8c8920d4ce4e..61770ea1c1c2 100644 --- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java +++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java @@ -133,6 +133,7 @@ import android.os.storage.StorageManager; import android.os.storage.VolumeInfo; import android.provider.DeviceConfig; import android.provider.Settings; +import android.security.metrics.CrashStats; import android.security.metrics.IKeystoreMetrics; import android.security.metrics.KeyCreationWithAuthInfo; import android.security.metrics.KeyCreationWithGeneralInfo; @@ -731,6 +732,7 @@ public class StatsPullAtomService extends SystemService { case FrameworkStatsLog.KEYSTORE2_KEY_OPERATION_WITH_PURPOSE_AND_MODES_INFO: case FrameworkStatsLog.KEYSTORE2_KEY_OPERATION_WITH_GENERAL_INFO: case FrameworkStatsLog.RKP_ERROR_STATS: + case FrameworkStatsLog.KEYSTORE2_CRASH_STATS: return pullKeystoreAtoms(atomTag, data); default: throw new UnsupportedOperationException("Unknown tagId=" + atomTag); @@ -927,6 +929,7 @@ public class StatsPullAtomService extends SystemService { registerKeystoreKeyOperationWithPurposeAndModesInfo(); registerKeystoreKeyOperationWithGeneralInfo(); registerRkpErrorStats(); + registerKeystoreCrashStats(); } private void initAndRegisterNetworkStatsPullers() { @@ -4139,6 +4142,14 @@ public class StatsPullAtomService extends SystemService { mStatsCallbackImpl); } + private void registerKeystoreCrashStats() { + mStatsManager.setPullAtomCallback( + FrameworkStatsLog.KEYSTORE2_CRASH_STATS, + null, // use default PullAtomMetadata values, + DIRECT_EXECUTOR, + mStatsCallbackImpl); + } + int parseKeystoreStorageStats(KeystoreAtom[] atoms, List<StatsEvent> pulledData) { for (KeystoreAtom atomWrapper : atoms) { if (atomWrapper.payload.getTag() != KeystoreAtomPayload.storageStats) { @@ -4271,6 +4282,19 @@ public class StatsPullAtomService extends SystemService { return StatsManager.PULL_SUCCESS; } + int parseKeystoreCrashStats(KeystoreAtom[] atoms, + List<StatsEvent> pulledData) { + for (KeystoreAtom atomWrapper : atoms) { + if (atomWrapper.payload.getTag() != KeystoreAtomPayload.crashStats) { + return StatsManager.PULL_SKIP; + } + CrashStats atom = atomWrapper.payload.getCrashStats(); + pulledData.add(FrameworkStatsLog.buildStatsEvent( + FrameworkStatsLog.KEYSTORE2_CRASH_STATS, atom.count_of_crash_events)); + } + return StatsManager.PULL_SUCCESS; + } + int pullKeystoreAtoms(int atomTag, List<StatsEvent> pulledData) { IKeystoreMetrics keystoreMetricsService = getIKeystoreMetricsService(); if (keystoreMetricsService == null) { @@ -4299,6 +4323,8 @@ public class StatsPullAtomService extends SystemService { return parseKeystoreKeyOperationWithGeneralInfo(atoms, pulledData); case FrameworkStatsLog.RKP_ERROR_STATS: return parseRkpErrorStats(atoms, pulledData); + case FrameworkStatsLog.KEYSTORE2_CRASH_STATS: + return parseKeystoreCrashStats(atoms, pulledData); default: Slog.w(TAG, "Unsupported keystore atom: " + atomTag); return StatsManager.PULL_SKIP; diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java index a436e6b3787b..d95e826339a1 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java @@ -22,6 +22,7 @@ import android.hardware.fingerprint.IUdfpsHbmListener; import android.os.Bundle; import android.os.IBinder; import android.os.ParcelFileDescriptor; +import android.view.InsetsState; import android.view.InsetsState.InternalInsetsType; import android.view.WindowInsetsController.Appearance; import android.view.WindowInsetsController.Behavior; @@ -132,7 +133,7 @@ public interface StatusBarManagerInternal { /** @see com.android.internal.statusbar.IStatusBar#onSystemBarAttributesChanged */ void onSystemBarAttributesChanged(int displayId, @Appearance int appearance, AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme, - @Behavior int behavior, boolean isFullscreen); + @Behavior int behavior, InsetsState requestedState, String packageName); /** @see com.android.internal.statusbar.IStatusBar#showTransient */ void showTransient(int displayId, @InternalInsetsType int[] types); diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index 6255d77dc7cd..47fdc4e5179a 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -59,6 +59,7 @@ import android.util.ArraySet; import android.util.Pair; import android.util.Slog; import android.util.SparseArray; +import android.view.InsetsState; import android.view.InsetsState.InternalInsetsType; import android.view.WindowInsetsController.Appearance; import android.view.WindowInsetsController.Behavior; @@ -526,13 +527,13 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D @Override public void onSystemBarAttributesChanged(int displayId, @Appearance int appearance, AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme, - @Behavior int behavior, boolean isFullscreen) { + @Behavior int behavior, InsetsState requestedState, String packageName) { getUiState(displayId).setBarAttributes(appearance, appearanceRegions, - navbarColorManagedByIme, behavior, isFullscreen); + navbarColorManagedByIme, behavior, requestedState, packageName); if (mBar != null) { try { mBar.onSystemBarAttributesChanged(displayId, appearance, appearanceRegions, - navbarColorManagedByIme, behavior, isFullscreen); + navbarColorManagedByIme, behavior, requestedState, packageName); } catch (RemoteException ex) { } } } @@ -671,20 +672,8 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D @Override public void collapsePanels() { - int uid = Binder.getCallingUid(); - int pid = Binder.getCallingPid(); - if (CompatChanges.isChangeEnabled(LOCK_DOWN_COLLAPSE_STATUS_BAR, uid)) { - enforceStatusBar(); - } else { - if (mContext.checkPermission(Manifest.permission.STATUS_BAR, pid, uid) - != PackageManager.PERMISSION_GRANTED) { - enforceExpandStatusBar(); - if (!mActivityTaskManager.canCloseSystemDialogs(pid, uid)) { - Slog.e(TAG, "Permission Denial: Method collapsePanels() requires permission " - + Manifest.permission.STATUS_BAR + ", ignoring call."); - return; - } - } + if (!checkCanCollapseStatusBar("collapsePanels")) { + return; } if (mBar != null) { @@ -697,7 +686,9 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D @Override public void togglePanel() { - enforceExpandStatusBar(); + if (!checkCanCollapseStatusBar("togglePanel")) { + return; + } if (isDisable2FlagSet(DISABLE2_NOTIFICATION_SHADE)) { return; @@ -758,7 +749,9 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D @Override public void handleSystemKey(int key) throws RemoteException { - enforceExpandStatusBar(); + if (!checkCanCollapseStatusBar("handleSystemKey")) { + return; + } if (mBar != null) { try { @@ -1111,13 +1104,14 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D return state; } - private class UiState { + private static class UiState { private @Appearance int mAppearance = 0; private AppearanceRegion[] mAppearanceRegions = new AppearanceRegion[0]; - private ArraySet<Integer> mTransientBarTypes = new ArraySet<>(); + private final ArraySet<Integer> mTransientBarTypes = new ArraySet<>(); private boolean mNavbarColorManagedByIme = false; private @Behavior int mBehavior; - private boolean mFullscreen = false; + private InsetsState mRequestedState = new InsetsState(); + private String mPackageName = "none"; private int mDisabled1 = 0; private int mDisabled2 = 0; private int mImeWindowVis = 0; @@ -1127,12 +1121,13 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D private void setBarAttributes(@Appearance int appearance, AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme, - @Behavior int behavior, boolean isFullscreen) { + @Behavior int behavior, InsetsState requestedState, String packageName) { mAppearance = appearance; mAppearanceRegions = appearanceRegions; mNavbarColorManagedByIme = navbarColorManagedByIme; mBehavior = behavior; - mFullscreen = isFullscreen; + mRequestedState = requestedState; + mPackageName = packageName; } private void showTransient(@InternalInsetsType int[] types) { @@ -1201,6 +1196,29 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D "StatusBarManagerService"); } + /** + * For targetSdk S+ we require STATUS_BAR. For targetSdk < S, we only require EXPAND_STATUS_BAR + * but also require that it falls into one of the allowed use-cases to lock down abuse vector. + */ + private boolean checkCanCollapseStatusBar(String method) { + int uid = Binder.getCallingUid(); + int pid = Binder.getCallingUid(); + if (CompatChanges.isChangeEnabled(LOCK_DOWN_COLLAPSE_STATUS_BAR, uid)) { + enforceStatusBar(); + } else { + if (mContext.checkPermission(Manifest.permission.STATUS_BAR, pid, uid) + != PackageManager.PERMISSION_GRANTED) { + enforceExpandStatusBar(); + if (!mActivityTaskManager.canCloseSystemDialogs(pid, uid)) { + Slog.e(TAG, "Permission Denial: Method " + method + "() requires permission " + + Manifest.permission.STATUS_BAR + ", ignoring call."); + return false; + } + } + } + return true; + } + // ================================================================================ // Callbacks from the status bar service. // ================================================================================ @@ -1229,8 +1247,8 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D state.mAppearance, state.mAppearanceRegions, state.mImeWindowVis, state.mImeBackDisposition, state.mShowImeSwitcher, gatherDisableActionsLocked(mCurrentUserId, 2), state.mImeToken, - state.mNavbarColorManagedByIme, state.mBehavior, state.mFullscreen, - transientBarTypes); + state.mNavbarColorManagedByIme, state.mBehavior, state.mRequestedState, + state.mPackageName, transientBarTypes); } } diff --git a/services/core/java/com/android/server/uri/UriGrantsManagerService.java b/services/core/java/com/android/server/uri/UriGrantsManagerService.java index 44545ed4898a..4e453f378cbc 100644 --- a/services/core/java/com/android/server/uri/UriGrantsManagerService.java +++ b/services/core/java/com/android/server/uri/UriGrantsManagerService.java @@ -1061,6 +1061,12 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub { PackageManager.GET_URI_PERMISSION_PATTERNS | pmFlags, userHandle); } + private ProviderInfo getProviderInfo(String authority, int userHandle, int pmFlags, + int callingUid) { + return mPmInternal.resolveContentProvider(authority, + PackageManager.GET_URI_PERMISSION_PATTERNS | pmFlags, userHandle, callingUid); + } + /** * Check if the targetPkg can be granted permission to access uri by * the callingUid using the given modeFlags. Throws a security exception @@ -1106,7 +1112,7 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub { final String authority = grantUri.uri.getAuthority(); final ProviderInfo pi = getProviderInfo(authority, grantUri.sourceUserId, - MATCH_DEBUG_TRIAGED_MISSING); + MATCH_DEBUG_TRIAGED_MISSING, callingUid); if (pi == null) { Slog.w(TAG, "No content provider found for permission check: " + grantUri.uri.toSafeString()); diff --git a/services/core/java/com/android/server/vibrator/VibratorManagerService.java b/services/core/java/com/android/server/vibrator/VibratorManagerService.java index fb8498ec73c1..2a47512bb147 100644 --- a/services/core/java/com/android/server/vibrator/VibratorManagerService.java +++ b/services/core/java/com/android/server/vibrator/VibratorManagerService.java @@ -1301,7 +1301,8 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { } /** Implementation of {@link IExternalVibratorService} to be triggered on external control. */ - private final class ExternalVibratorService extends IExternalVibratorService.Stub { + @VisibleForTesting + final class ExternalVibratorService extends IExternalVibratorService.Stub { ExternalVibrationDeathRecipient mCurrentExternalDeathRecipient; @Override @@ -1332,6 +1333,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { return vibHolder.scale; } + ExternalVibrationHolder cancelingExternalVibration = null; VibrationThread cancelingVibration = null; int scale; synchronized (mLock) { @@ -1350,16 +1352,18 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { cancelingVibration = mCurrentVibration; } } else { + // At this point we have an externally controlled vibration playing already. + // Since the interface defines that only one externally controlled vibration can + // play at a time, we need to first mute the ongoing vibration and then return + // a scale from this function for the new one. Ee can be assured that the + // ongoing it will be muted in favor of the new vibration. + // + // Note that this doesn't support multiple concurrent external controls, as we + // would need to mute the old one still if it came from a different controller. + mCurrentExternalVibration.externalVibration.mute(); endVibrationLocked(mCurrentExternalVibration, Vibration.Status.CANCELLED); + cancelingExternalVibration = mCurrentExternalVibration; } - // At this point we either have an externally controlled vibration playing, or - // no vibration playing. Since the interface defines that only one externally - // controlled vibration can play at a time, by returning something other than - // SCALE_MUTE from this function we can be assured that if we are currently - // playing vibration, it will be muted in favor of the new vibration. - // - // Note that this doesn't support multiple concurrent external controls, as we - // would need to mute the old one still if it came from a different controller. mCurrentExternalVibration = new ExternalVibrationHolder(vib); mCurrentExternalDeathRecipient = new ExternalVibrationDeathRecipient(); vib.linkToDeath(mCurrentExternalDeathRecipient); @@ -1376,10 +1380,14 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { + "external control", e); } } - if (DEBUG) { - Slog.d(TAG, "Vibrator going under external control."); + if (cancelingExternalVibration == null) { + // We only need to set external control if it was not already set by another + // external vibration. + if (DEBUG) { + Slog.d(TAG, "Vibrator going under external control."); + } + setExternalControl(true); } - setExternalControl(true); if (DEBUG) { Slog.e(TAG, "Playing external vibration: " + vib); } diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java index a975ba6096ed..8a76e3e586e0 100644 --- a/services/core/java/com/android/server/wm/ActivityClientController.java +++ b/services/core/java/com/android/server/wm/ActivityClientController.java @@ -1076,8 +1076,7 @@ class ActivityClientController extends IActivityClientController.Stub { } } - @Override - public void restartActivityProcessIfVisible(IBinder token) { + void restartActivityProcessIfVisible(IBinder token) { ActivityTaskManagerService.enforceTaskPermission("restartActivityProcess"); final long callingId = Binder.clearCallingIdentity(); try { diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 5eba87dff5f7..abc2b7aabb6b 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -5142,6 +5142,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // Reset the last saved PiP snap fraction on app stop. mDisplayContent.mPinnedTaskController.onActivityHidden(mActivityComponent); mDisplayContent.mUnknownAppVisibilityController.appRemovedOrHidden(this); + if (isClientVisible()) { + // Though this is usually unlikely to happen, still make sure the client is invisible. + setClientVisible(false); + } destroySurfaces(); // Remove any starting window that was added for this app if they are still around. removeStartingWindow(); @@ -5270,7 +5274,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // returns. Just need to confirm this reasoning makes sense. final boolean deferHidingClient = canEnterPictureInPicture && !isState(STARTED, STOPPING, STOPPED, PAUSED); - if (deferHidingClient && pictureInPictureArgs.isAutoEnterEnabled()) { + if (!mAtmService.getTransitionController().isShellTransitionsEnabled() + && deferHidingClient && pictureInPictureArgs.isAutoEnterEnabled()) { // Go ahead and just put the activity in pip if it supports auto-pip. mAtmService.enterPictureInPictureMode(this, pictureInPictureArgs); return; @@ -8178,7 +8183,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A if (shouldRelaunchLocked(changes, mTmpConfig) || forceNewConfig) { // Aha, the activity isn't handling the change, so DIE DIE DIE. configChangeFlags |= changes; - startFreezingScreenLocked(globalChanges); + if (!mAtmService.getTransitionController().isShellTransitionsEnabled()) { + startFreezingScreenLocked(globalChanges); + } forceNewConfig = false; preserveWindow &= isResizeOnlyChange(changes); final boolean hasResizeChange = hasResizeChange(changes & ~info.getRealConfigChanged()); diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java index b6f2f243040e..d08d285beda8 100644 --- a/services/core/java/com/android/server/wm/ActivityStartController.java +++ b/services/core/java/com/android/server/wm/ActivityStartController.java @@ -27,6 +27,7 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.ActivityTaskSupervisor.ON_TOP; +import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityOptions; import android.app.IApplicationThread; @@ -38,6 +39,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.os.Binder; +import android.os.Bundle; import android.os.IBinder; import android.os.UserHandle; import android.provider.Settings; @@ -488,6 +490,16 @@ public class ActivityStartController { return START_SUCCESS; } + void startActivityInTaskFragment(@NonNull TaskFragment taskFragment, + @NonNull Intent activityIntent, @Nullable Bundle activityOptions) { + obtainStarter(activityIntent, "startActivityInTaskFragment") + .setActivityOptions(activityOptions) + .setInTaskFragment(taskFragment) + .setCallingUid(Binder.getCallingUid()) + .setCallingPid(Binder.getCallingPid()) + .execute(); + } + void registerRemoteAnimationForNextActivityStart(String packageName, RemoteAnimationAdapter adapter) { mPendingRemoteAnimationRegistry.addPendingAnimation(packageName, adapter); diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index 3dc4892c874c..ff7cb123b65b 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -87,6 +87,7 @@ import android.app.IApplicationThread; import android.app.PendingIntent; import android.app.ProfilerInfo; import android.app.WaitResult; +import android.content.ComponentName; import android.content.IIntentSender; import android.content.Intent; import android.content.IntentSender; @@ -177,6 +178,7 @@ class ActivityStarter { private int mPreferredWindowingMode; private Task mInTask; + private TaskFragment mInTaskFragment; @VisibleForTesting boolean mAddingToTask; private Task mReuseTask; @@ -342,6 +344,7 @@ class ActivityStarter { boolean avoidMoveToFront; ActivityRecord[] outActivity; Task inTask; + TaskFragment inTaskFragment; String reason; ProfilerInfo profilerInfo; Configuration globalConfig; @@ -392,6 +395,7 @@ class ActivityStarter { componentSpecified = false; outActivity = null; inTask = null; + inTaskFragment = null; reason = null; profilerInfo = null; globalConfig = null; @@ -407,7 +411,7 @@ class ActivityStarter { /** * Adopts all values from passed in request. */ - void set(Request request) { + void set(@NonNull Request request) { caller = request.caller; intent = request.intent; intentGrants = request.intentGrants; @@ -432,6 +436,7 @@ class ActivityStarter { componentSpecified = request.componentSpecified; outActivity = request.outActivity; inTask = request.inTask; + inTaskFragment = request.inTaskFragment; reason = request.reason; profilerInfo = request.profilerInfo; globalConfig = request.globalConfig; @@ -574,6 +579,7 @@ class ActivityStarter { mPreferredWindowingMode = starter.mPreferredWindowingMode; mInTask = starter.mInTask; + mInTaskFragment = starter.mInTaskFragment; mAddingToTask = starter.mAddingToTask; mReuseTask = starter.mReuseTask; @@ -835,6 +841,7 @@ class ActivityStarter { final int startFlags = request.startFlags; final SafeActivityOptions options = request.activityOptions; Task inTask = request.inTask; + TaskFragment inTaskFragment = request.inTaskFragment; int err = ActivityManager.START_SUCCESS; // Pull the optional Ephemeral Installer-only bundle out of the options early. @@ -1175,8 +1182,8 @@ class ActivityStarter { } mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession, - request.voiceInteractor, startFlags, true /* doResume */, checkedOptions, inTask, - restrictedBgActivity, intentGrants); + request.voiceInteractor, startFlags, true /* doResume */, checkedOptions, + inTask, inTaskFragment, restrictedBgActivity, intentGrants); if (request.outActivity != null) { request.outActivity[0] = mLastStartActivityRecord; @@ -1222,6 +1229,20 @@ class ActivityStarter { mController.onExecutionComplete(this); } + private boolean isHomeApp(int uid, @Nullable String packageName) { + if (mService.mHomeProcess != null) { + // Fast check + return uid == mService.mHomeProcess.mUid; + } + if (packageName == null) { + return false; + } + ComponentName activity = + mService.getPackageManagerInternalLocked().getDefaultHomeActivity( + UserHandle.getUserId(uid)); + return activity != null && packageName.equals(activity.getPackageName()); + } + boolean shouldAbortBackgroundActivityStart(int callingUid, int callingPid, final String callingPackage, int realCallingUid, int realCallingPid, WindowProcessController callerApp, PendingIntentRecord originatingPendingIntent, @@ -1237,7 +1258,7 @@ class ActivityStarter { } // Always allow home application to start activities. - if (mService.mHomeProcess != null && callingUid == mService.mHomeProcess.mUid) { + if (isHomeApp(callingUid, callingPackage)) { if (DEBUG_ACTIVITY_STARTS) { Slog.d(TAG, "Activity start allowed for home app callingUid (" + callingUid + ")"); } @@ -1532,9 +1553,10 @@ class ActivityStarter { * Here also ensures that the starting activity is removed if the start wasn't successful. */ private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord, - IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, - int startFlags, boolean doResume, ActivityOptions options, Task inTask, - boolean restrictedBgActivity, NeededUriGrants intentGrants) { + IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, + int startFlags, boolean doResume, ActivityOptions options, Task inTask, + TaskFragment inTaskFragment, boolean restrictedBgActivity, + NeededUriGrants intentGrants) { int result = START_CANCELED; final Task startedActivityRootTask; @@ -1559,7 +1581,8 @@ class ActivityStarter { mService.deferWindowLayout(); Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "startActivityInner"); result = startActivityInner(r, sourceRecord, voiceSession, voiceInteractor, - startFlags, doResume, options, inTask, restrictedBgActivity, intentGrants); + startFlags, doResume, options, inTask, inTaskFragment, restrictedBgActivity, + intentGrants); } finally { Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); startedActivityRootTask = handleStartResult(r, result); @@ -1662,9 +1685,10 @@ class ActivityStarter { int startActivityInner(final ActivityRecord r, ActivityRecord sourceRecord, IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, int startFlags, boolean doResume, ActivityOptions options, Task inTask, - boolean restrictedBgActivity, NeededUriGrants intentGrants) { - setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession, - voiceInteractor, restrictedBgActivity); + TaskFragment inTaskFragment, boolean restrictedBgActivity, + NeededUriGrants intentGrants) { + setInitialState(r, options, inTask, inTaskFragment, doResume, startFlags, sourceRecord, + voiceSession, voiceInteractor, restrictedBgActivity); computeLaunchingTaskFlags(); @@ -2204,6 +2228,7 @@ class ActivityStarter { mPreferredWindowingMode = WINDOWING_MODE_UNDEFINED; mInTask = null; + mInTaskFragment = null; mAddingToTask = false; mReuseTask = null; @@ -2231,9 +2256,9 @@ class ActivityStarter { } private void setInitialState(ActivityRecord r, ActivityOptions options, Task inTask, - boolean doResume, int startFlags, ActivityRecord sourceRecord, - IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, - boolean restrictedBgActivity) { + TaskFragment inTaskFragment, boolean doResume, int startFlags, + ActivityRecord sourceRecord, IVoiceInteractionSession voiceSession, + IVoiceInteractor voiceInteractor, boolean restrictedBgActivity) { reset(false /* clearRequest */); mStartActivity = r; @@ -2336,6 +2361,7 @@ class ActivityStarter { Slog.w(TAG, "Starting activity in task not in recents: " + inTask); mInTask = null; } + mInTaskFragment = inTaskFragment; mStartFlags = startFlags; // If the onlyIfNeeded flag is set, then we can do this if the activity being launched @@ -2691,11 +2717,23 @@ class ActivityStarter { mIntentDelivered = true; } - private void addOrReparentStartingActivity(Task parent, String reason) { - if (mStartActivity.getTask() == null || mStartActivity.getTask() == parent) { - parent.addChild(mStartActivity); + private void addOrReparentStartingActivity(@NonNull Task task, String reason) { + TaskFragment newParent = task; + if (mInTaskFragment != null) { + // mInTaskFragment is created and added to the leaf task by task fragment organizer's + // request. If the task was resolved and different than mInTaskFragment, reparent the + // task to mInTaskFragment for embedding. + if (mInTaskFragment.getTask() != task) { + task.reparent(mInTaskFragment, POSITION_TOP); + } else { + newParent = mInTaskFragment; + } + } + if (mStartActivity.getTaskFragment() == null + || mStartActivity.getTaskFragment() == newParent) { + newParent.addChild(mStartActivity, POSITION_TOP); } else { - mStartActivity.reparent(parent, parent.getChildCount() /* top */, reason); + mStartActivity.reparent(newParent, newParent.getChildCount() /* top */, reason); } } @@ -2927,6 +2965,11 @@ class ActivityStarter { return this; } + ActivityStarter setInTaskFragment(TaskFragment taskFragment) { + mRequest.inTaskFragment = taskFragment; + return this; + } + ActivityStarter setWaitResult(WaitResult result) { mRequest.waitResult = result; return this; @@ -3010,5 +3053,7 @@ class ActivityStarter { pw.print(mDoResume); pw.print(" mAddingToTask="); pw.println(mAddingToTask); + pw.print(" mInTaskFragment="); + pw.println(mInTaskFragment); } } diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 2aaf6f7f40ad..56095bb9f31f 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -1881,25 +1881,42 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public void setFocusedTask(int taskId) { enforceTaskPermission("setFocusedTask()"); - ProtoLog.d(WM_DEBUG_FOCUS, "setFocusedTask: taskId=%d", taskId); final long callingId = Binder.clearCallingIdentity(); try { synchronized (mGlobalLock) { - final Task task = mRootWindowContainer.anyTaskForId(taskId, - MATCH_ATTACHED_TASK_ONLY); - if (task == null) { - return; - } - final ActivityRecord r = task.topRunningActivityLocked(); - if (r != null && r.moveFocusableActivityToTop("setFocusedTask")) { - mRootWindowContainer.resumeFocusedTasksTopActivities(); - } + setFocusedTask(taskId, null /* touchedActivity */); } } finally { Binder.restoreCallingIdentity(callingId); } } + void setFocusedTask(int taskId, ActivityRecord touchedActivity) { + ProtoLog.d(WM_DEBUG_FOCUS, "setFocusedTask: taskId=%d touchedActivity=%s", taskId, + touchedActivity); + final Task task = mRootWindowContainer.anyTaskForId(taskId, MATCH_ATTACHED_TASK_ONLY); + if (task == null) { + return; + } + final ActivityRecord r = task.topRunningActivityLocked(); + if (r == null) { + return; + } + + if (r.moveFocusableActivityToTop("setFocusedTask")) { + mRootWindowContainer.resumeFocusedTasksTopActivities(); + } else if (touchedActivity != null && touchedActivity != r + && touchedActivity.getTask() == r.getTask() + && touchedActivity.getTaskFragment() != r.getTaskFragment()) { + // Set the focused app directly since the focused window is not on the + // top-most TaskFragment of the top-most Task + final DisplayContent displayContent = touchedActivity.getDisplayContent(); + displayContent.setFocusedApp(touchedActivity); + mWindowManager.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, + true /* updateInputWindows */); + } + } + @Override public boolean removeTask(int taskId) { mAmInternal.enforceCallingPermission(REMOVE_TASKS, "removeTask()"); @@ -5069,6 +5086,34 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { process.registerDisplayAreaConfigurationListener(imeContainer); } + @Override + public void setRunningRemoteTransitionDelegate(IApplicationThread caller) { + mAmInternal.enforceCallingPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS, + "setRunningRemoteTransition"); + final int callingPid = Binder.getCallingPid(); + final int callingUid = Binder.getCallingUid(); + synchronized (mGlobalLock) { + // Also only allow a process which is already runningRemoteAnimation to mark another + // process. + final WindowProcessController callingProc = getProcessController(callingPid, + callingUid); + if (callingProc == null || !callingProc.isRunningRemoteTransition()) { + final String msg = "Can't call setRunningRemoteTransition from a process (pid=" + + callingPid + " uid=" + callingUid + ") which isn't itself running a " + + "remote transition."; + Slog.e(TAG, msg); + throw new SecurityException(msg); + } + final WindowProcessController wpc = getProcessController(caller); + if (wpc == null) { + Slog.w(TAG, "Unable to find process for application " + caller); + return; + } + wpc.setRunningRemoteAnimation(true /* running */); + callingProc.addRemoteAnimationDelegate(wpc); + } + } + final class H extends Handler { static final int REPORT_TIME_TRACKER_MSG = 1; static final int UPDATE_PROCESS_ANIMATING_STATE = 2; @@ -6485,12 +6530,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { Slog.w(TAG, "Override application configuration: cannot find pid " + mPid); return; } - if (wpc.getNightMode() == mNightMode) { - return; - } - if (!wpc.setOverrideNightMode(mNightMode)) { - return; - } + wpc.setOverrideNightMode(mNightMode); wpc.updateNightModeForAllActivities(mNightMode); mPackageConfigPersister.updateFromImpl(wpc.mName, wpc.mUserId, this); } finally { diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java index 08bca353f910..74efe0c7422f 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java @@ -347,6 +347,12 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { */ private int mVisibilityTransactionDepth; + /** + * Whether to the visibility updates that started from {@code RootWindowContainer} should be + * deferred. + */ + private boolean mDeferRootVisibilityUpdate; + private ActivityMetricsLogger mActivityMetricsLogger; /** Check if placing task or activity on specified display is allowed. */ @@ -2263,6 +2269,14 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { return mVisibilityTransactionDepth > 0; } + void setDeferRootVisibilityUpdate(boolean deferUpdate) { + mDeferRootVisibilityUpdate = deferUpdate; + } + + boolean isRootVisibilityUpdateDeferred() { + return mDeferRootVisibilityUpdate; + } + /** * Called when the state or visibility of an attached activity is changed. * diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java index 2eeabf2b17ef..6fafc0291427 100644 --- a/services/core/java/com/android/server/wm/ConfigurationContainer.java +++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java @@ -550,8 +550,8 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> { * @return true if the nightMode has been changed. */ public boolean setOverrideNightMode(int nightMode) { - final int currentUiMode = mFullConfiguration.uiMode; - final int currentNightMode = getNightMode(); + final int currentUiMode = mRequestedOverrideConfiguration.uiMode; + final int currentNightMode = currentUiMode & Configuration.UI_MODE_NIGHT_MASK; final int validNightMode = nightMode & Configuration.UI_MODE_NIGHT_MASK; if (currentNightMode == validNightMode) { return false; @@ -563,10 +563,6 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> { return true; } - int getNightMode() { - return mFullConfiguration.uiMode & Configuration.UI_MODE_NIGHT_MASK; - } - public boolean isActivityTypeDream() { return getActivityType() == ACTIVITY_TYPE_DREAM; } diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index f5c2db08c4c6..632662d5e7cc 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -772,6 +772,12 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp mTmpWindow = null; return true; } + + if (focusedApp.getTask() == activity.getTask() + && focusedApp.getTaskFragment() != activity.getTaskFragment()) { + // Do not use the activity window of another TaskFragment in the same leaf Task + return false; + } } ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "findFocusedWindow: Found new focus @ %s", w); diff --git a/services/core/java/com/android/server/wm/DisplayHashController.java b/services/core/java/com/android/server/wm/DisplayHashController.java index 0cf4379da02a..64a57588113c 100644 --- a/services/core/java/com/android/server/wm/DisplayHashController.java +++ b/services/core/java/com/android/server/wm/DisplayHashController.java @@ -47,7 +47,6 @@ import android.os.Looper; import android.os.Message; import android.os.RemoteCallback; import android.os.RemoteException; -import android.os.UserHandle; import android.service.displayhash.DisplayHashParams; import android.service.displayhash.DisplayHashingService; import android.service.displayhash.IDisplayHashingService; @@ -380,8 +379,7 @@ public class DisplayHashController { intent.setComponent(component); final long token = Binder.clearCallingIdentity(); try { - mContext.bindServiceAsUser(intent, mServiceConnection, - Context.BIND_AUTO_CREATE, UserHandle.CURRENT); + mContext.bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE); if (DEBUG) Slog.v(TAG, "bound"); } finally { Binder.restoreCallingIdentity(token); @@ -404,8 +402,15 @@ public class DisplayHashController { final Intent intent = new Intent(DisplayHashingService.SERVICE_INTERFACE); intent.setPackage(packageName); - final ResolveInfo resolveInfo = mContext.getPackageManager().resolveService(intent, - PackageManager.GET_SERVICES | PackageManager.GET_META_DATA); + final ResolveInfo resolveInfo; + final long token = Binder.clearCallingIdentity(); + try { + resolveInfo = mContext.getPackageManager().resolveService(intent, + PackageManager.GET_SERVICES | PackageManager.GET_META_DATA); + } finally { + Binder.restoreCallingIdentity(token); + } + if (resolveInfo == null || resolveInfo.serviceInfo == null) { Slog.w(TAG, "No valid components found."); return null; diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index e5ea69866d10..d5a4345cb073 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -175,6 +175,7 @@ import com.android.server.wallpaper.WallpaperManagerInternal; import com.android.server.wm.InputMonitor.EventReceiverInputConsumer; import java.io.PrintWriter; +import java.util.Objects; import java.util.function.Consumer; /** @@ -322,17 +323,19 @@ public class DisplayPolicy { // needs to be opaque. private WindowState mNavBarBackgroundWindow; + private String mFocusedApp; private int mLastDisableFlags; private int mLastAppearance; private int mLastFullscreenAppearance; private int mLastDockedAppearance; private int mLastBehavior; + private final InsetsState mRequestedState = new InsetsState(); private final Rect mNonDockedRootTaskBounds = new Rect(); private final Rect mDockedRootTaskBounds = new Rect(); private final Rect mLastNonDockedRootTaskBounds = new Rect(); private final Rect mLastDockedRootTaskBounds = new Rect(); - // What we last reported to system UI about whether the focused window is fullscreen/immersive. + // What we last reported to input dispatcher about whether the focused window is fullscreen. private boolean mLastFocusIsFullscreen = false; // If nonzero, a panic gesture was performed at that time in uptime millis and is still pending. @@ -2683,6 +2686,8 @@ public class DisplayPolicy { && mLastFullscreenAppearance == fullscreenAppearance && mLastDockedAppearance == dockedAppearance && mLastBehavior == behavior + && mRequestedState.equals(win.getRequestedState()) + && Objects.equals(mFocusedApp, win.mAttrs.packageName) && mLastFocusIsFullscreen == isFullscreen && mLastNonDockedRootTaskBounds.equals(mNonDockedRootTaskBounds) && mLastDockedRootTaskBounds.equals(mDockedRootTaskBounds)) { @@ -2698,6 +2703,8 @@ public class DisplayPolicy { mLastFullscreenAppearance = fullscreenAppearance; mLastDockedAppearance = dockedAppearance; mLastBehavior = behavior; + mRequestedState.set(win.getRequestedState(), true /* copySources */); + mFocusedApp = win.mAttrs.packageName; mLastFocusIsFullscreen = isFullscreen; mLastNonDockedRootTaskBounds.set(mNonDockedRootTaskBounds); mLastDockedRootTaskBounds.set(mDockedRootTaskBounds); @@ -2716,7 +2723,7 @@ public class DisplayPolicy { final int displayId = getDisplayId(); statusBar.setDisableFlags(displayId, disableFlags, cause); statusBar.onSystemBarAttributesChanged(displayId, appearance, appearanceRegions, - isNavbarColorManagedByIme, behavior, isFullscreen); + isNavbarColorManagedByIme, behavior, mRequestedState, mFocusedApp); } }); diff --git a/services/core/java/com/android/server/wm/Letterbox.java b/services/core/java/com/android/server/wm/Letterbox.java index 3dbe79df6722..5a249a5599bb 100644 --- a/services/core/java/com/android/server/wm/Letterbox.java +++ b/services/core/java/com/android/server/wm/Letterbox.java @@ -58,10 +58,12 @@ public class Letterbox { private final LetterboxSurface mLeft = new LetterboxSurface("left"); private final LetterboxSurface mBottom = new LetterboxSurface("bottom"); private final LetterboxSurface mRight = new LetterboxSurface("right"); - // Prevents wallpaper from peeking through near rounded corners. It's not included in - // mSurfaces array since it isn't needed in methods like notIntersectsOrFullyContains - // or attachInput. - private final LetterboxSurface mBehind = new LetterboxSurface("behind"); + // One surface that fills the whole window is used over multiple surfaces to: + // - Prevents wallpaper from peeking through near rounded corners. + // - For "blurred wallpaper" background, to avoid having visible border between surfaces. + // One surface approach isn't always preferred over multiple surfaces due to rendering cost + // for overlaping an app window and letterbox surfaces. + private final LetterboxSurface mFullWindowSurface = new LetterboxSurface("fullWindow"); private final LetterboxSurface[] mSurfaces = { mLeft, mTop, mRight, mBottom }; /** @@ -104,7 +106,7 @@ public class Letterbox { mLeft.layout(outer.left, outer.top, inner.left, outer.bottom, surfaceOrigin); mBottom.layout(outer.left, inner.bottom, outer.right, outer.bottom, surfaceOrigin); mRight.layout(inner.right, outer.top, outer.right, outer.bottom, surfaceOrigin); - mBehind.layout(inner.left, inner.top, inner.right, inner.bottom, surfaceOrigin); + mFullWindowSurface.layout(outer.left, outer.top, outer.right, outer.bottom, surfaceOrigin); } @@ -168,37 +170,46 @@ public class Letterbox { for (LetterboxSurface surface : mSurfaces) { surface.remove(); } - mBehind.remove(); + mFullWindowSurface.remove(); } /** Returns whether a call to {@link #applySurfaceChanges} would change the surface. */ public boolean needsApplySurfaceChanges() { + if (useFullWindowSurface()) { + return mFullWindowSurface.needsApplySurfaceChanges(); + } for (LetterboxSurface surface : mSurfaces) { if (surface.needsApplySurfaceChanges()) { return true; } } - if (mAreCornersRounded.get() && mBehind.needsApplySurfaceChanges()) { - return true; - } return false; } public void applySurfaceChanges(SurfaceControl.Transaction t) { - for (LetterboxSurface surface : mSurfaces) { - surface.applySurfaceChanges(t); - } - if (mAreCornersRounded.get()) { - mBehind.applySurfaceChanges(t); + if (useFullWindowSurface()) { + mFullWindowSurface.applySurfaceChanges(t); + + for (LetterboxSurface surface : mSurfaces) { + surface.remove(); + } } else { - mBehind.remove(); + for (LetterboxSurface surface : mSurfaces) { + surface.applySurfaceChanges(t); + } + + mFullWindowSurface.remove(); } } /** Enables touches to slide into other neighboring surfaces. */ void attachInput(WindowState win) { - for (LetterboxSurface surface : mSurfaces) { - surface.attachInput(win); + if (useFullWindowSurface()) { + mFullWindowSurface.attachInput(win); + } else { + for (LetterboxSurface surface : mSurfaces) { + surface.attachInput(win); + } } } @@ -208,6 +219,16 @@ public class Letterbox { surface.mInputInterceptor.mWindowHandle.displayId = displayId; } } + if (mFullWindowSurface.mInputInterceptor != null) { + mFullWindowSurface.mInputInterceptor.mWindowHandle.displayId = displayId; + } + } + + /** + * Returns {@code true} when using {@link #mFullWindowSurface} instead of {@link mSurfaces}. + */ + private boolean useFullWindowSurface() { + return mAreCornersRounded.get() || mHasWallpaperBackgroundSupplier.get(); } private static class InputInterceptor { @@ -308,6 +329,10 @@ public class Letterbox { mInputInterceptor = new InputInterceptor("Letterbox_" + mType + "_", win); } + boolean isRemoved() { + return mSurface != null || mInputInterceptor != null; + } + public void remove() { if (mSurface != null) { mTransactionFactory.get().remove(mSurface).apply(); diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java index 737ef338f9b2..9e147b132682 100644 --- a/services/core/java/com/android/server/wm/RecentsAnimationController.java +++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java @@ -952,7 +952,8 @@ public class RecentsAnimationController implements DeathRecipient { "cleanupAnimation(): Notify animation finished mPendingAnimations=%d " + "reorderMode=%d", mPendingAnimations.size(), reorderMode); - if (reorderMode != REORDER_MOVE_TO_ORIGINAL_POSITION) { + if (reorderMode != REORDER_MOVE_TO_ORIGINAL_POSITION + && mTargetActivityRecord != mDisplayContent.topRunningActivity()) { // Notify the state at the beginning because the removeAnimation may notify the // transition is finished. This is a signal that there will be a next transition. mDisplayContent.mFixedRotationTransitionListener.notifyRecentsWillBeTop(); @@ -1029,7 +1030,13 @@ public class RecentsAnimationController implements DeathRecipient { @Override public void binderDied() { - cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "binderDied"); + if (!mCanceled) { + cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "binderDied"); + } else { + // If we are already canceled but with a screenshot, and are waiting for the + // cleanupScreenshot() callback, then force-finish the animation now + continueDeferredCancelAnimation(); + } synchronized (mService.getWindowManagerLock()) { // Clear associated input consumers on runner death diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index 539bea2faef9..0b80bae71ab8 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -1973,7 +1973,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent> */ void ensureActivitiesVisible(ActivityRecord starting, int configChanges, boolean preserveWindows, boolean notifyClients) { - if (mTaskSupervisor.inActivityVisibilityUpdate()) { + if (mTaskSupervisor.inActivityVisibilityUpdate() + || mTaskSupervisor.isRootVisibilityUpdateDeferred()) { // Don't do recursive work. return; } diff --git a/services/core/java/com/android/server/wm/SafeActivityOptions.java b/services/core/java/com/android/server/wm/SafeActivityOptions.java index 4892005631ba..2d4aef682d62 100644 --- a/services/core/java/com/android/server/wm/SafeActivityOptions.java +++ b/services/core/java/com/android/server/wm/SafeActivityOptions.java @@ -78,6 +78,18 @@ public class SafeActivityOptions { } /** + * Constructs a new instance from a bundle and provided pid/uid. + * + * @param bOptions The {@link ActivityOptions} as {@link Bundle}. + */ + static SafeActivityOptions fromBundle(Bundle bOptions, int callingPid, int callingUid) { + return bOptions != null + ? new SafeActivityOptions(ActivityOptions.fromBundle(bOptions), + callingPid, callingUid) + : null; + } + + /** * Constructs a new instance and records {@link Binder#getCallingPid}/ * {@link Binder#getCallingUid}. Thus, calling identity MUST NOT be cleared when constructing * this object. @@ -91,6 +103,17 @@ public class SafeActivityOptions { } /** + * Constructs a new instance. + * + * @param options The options to wrap. + */ + private SafeActivityOptions(@Nullable ActivityOptions options, int callingPid, int callingUid) { + mOriginalCallingPid = callingPid; + mOriginalCallingUid = callingUid; + mOriginalOptions = options; + } + + /** * Overrides options with options from a caller and records {@link Binder#getCallingPid}/ * {@link Binder#getCallingUid}. Thus, calling identity MUST NOT be cleared when calling this * method. diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 1089f5a19a94..d8681f6a0c9d 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -629,7 +629,7 @@ class Task extends TaskFragment { IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor, boolean _createdByOrganizer, IBinder _launchCookie, boolean _deferTaskAppear, boolean _removeWithTaskOrganizer) { - super(atmService, _createdByOrganizer); + super(atmService, null /* fragmentToken */, _createdByOrganizer); mTaskId = _taskId; mUserId = _userId; @@ -643,7 +643,6 @@ class Task extends TaskFragment { : new PersistedTaskSnapshotData(); // Tasks have no set orientation value (including SCREEN_ORIENTATION_UNSPECIFIED). setOrientation(SCREEN_ORIENTATION_UNSET); - mRemoteToken = new RemoteToken(this); affinityIntent = _affinityIntent; affinity = _affinity; rootAffinity = _rootAffinity; @@ -3339,9 +3338,6 @@ class Task extends TaskFragment { info.topActivityInfo = mReuseActivitiesReport.top != null ? mReuseActivitiesReport.top.info : null; - info.topActivityToken = mReuseActivitiesReport.top != null - ? mReuseActivitiesReport.top.appToken - : null; // Whether the direct top activity is in size compat mode on foreground. info.topActivityInSizeCompat = mReuseActivitiesReport.top != null && mReuseActivitiesReport.top.getOrganizedTask() == this @@ -3369,9 +3365,9 @@ class Task extends TaskFragment { private @Nullable PictureInPictureParams getPictureInPictureParams(Task top) { if (top == null) return null; - final ActivityRecord topVisibleActivity = top.getTopVisibleActivity(); - return (topVisibleActivity == null || topVisibleActivity.pictureInPictureArgs.empty()) - ? null : new PictureInPictureParams(topVisibleActivity.pictureInPictureArgs); + final ActivityRecord topMostActivity = top.getTopMostActivity(); + return (topMostActivity == null || topMostActivity.pictureInPictureArgs.empty()) + ? null : new PictureInPictureParams(topMostActivity.pictureInPictureArgs); } /** @@ -4504,8 +4500,10 @@ class Task extends TaskFragment { mAtmService.continueWindowLayout(); } - mRootWindowContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS); - mRootWindowContainer.resumeFocusedTasksTopActivities(); + if (!mTaskSupervisor.isRootVisibilityUpdateDeferred()) { + mRootWindowContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS); + mRootWindowContainer.resumeFocusedTasksTopActivities(); + } } void resumeNextFocusAfterReparent() { @@ -4979,7 +4977,6 @@ class Task extends TaskFragment { // Slot the activity into the history root task and proceed ProtoLog.i(WM_DEBUG_ADD_REMOVE, "Adding activity %s to task %s " + "callers: %s", r, task, new RuntimeException("here").fillInStackTrace()); - task.positionChildAtTop(r); // The transition animation and starting window are not needed if {@code allowMoveToFront} // is false, because the activity won't be visible. diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java index b263909d7e6d..12ad634fb6b8 100644 --- a/services/core/java/com/android/server/wm/TaskFragment.java +++ b/services/core/java/com/android/server/wm/TaskFragment.java @@ -74,7 +74,6 @@ import android.app.servertransaction.ClientTransaction; import android.app.servertransaction.NewIntentItem; import android.app.servertransaction.PauseActivityItem; import android.app.servertransaction.ResumeActivityItem; -import android.content.ComponentName; import android.content.res.Configuration; import android.graphics.Rect; import android.os.IBinder; @@ -155,6 +154,9 @@ class TaskFragment extends WindowContainer<WindowContainer> { */ int mMinHeight; + /** Avoid reentrant of {@link #removeImmediately()}. */ + private boolean mRemoving; + // The TaskFragment that adjacent to this one. private TaskFragment mAdjacentTaskFragment; @@ -196,22 +198,19 @@ class TaskFragment extends WindowContainer<WindowContainer> { boolean mCreatedByOrganizer; /** Organizer that organizing this TaskFragment. */ - // TODO(b/190433129) set the value when creating TaskFragment from WCT. @Nullable private ITaskFragmentOrganizer mTaskFragmentOrganizer; /** Client assigned unique token for this TaskFragment if this is created by an organizer. */ - // TODO(b/190433129) set the value when creating TaskFragment from WCT. @Nullable private IBinder mFragmentToken; /** - * The component name of the root activity that initiated this TaskFragment, which will be used - * to configure the relationships for TaskFragments. + * The PID of the organizer that created this TaskFragment. It should be the same as the PID + * of {@link android.window.TaskFragmentCreationParams#getOwnerToken()}. + * {@link ActivityRecord#INVALID_PID} if this is not an organizer-created TaskFragment. */ - // TODO(b/190433129) set the value when creating TaskFragment from WCT. - @Nullable - private ComponentName mInitialComponentName; + private int mTaskFragmentOrganizerPid = ActivityRecord.INVALID_PID; private final Rect mTmpInsets = new Rect(); private final Rect mTmpBounds = new Rect(); @@ -260,15 +259,18 @@ class TaskFragment extends WindowContainer<WindowContainer> { } } - TaskFragment(ActivityTaskManagerService atmService, boolean createdByOrganizer) { + TaskFragment(ActivityTaskManagerService atmService, IBinder fragmentToken, + boolean createdByOrganizer) { super(atmService.mWindowManager); mAtmService = atmService; - mTaskSupervisor = atmService.mTaskSupervisor; + mTaskSupervisor = mAtmService.mTaskSupervisor; mRootWindowContainer = mAtmService.mRootWindowContainer; mCreatedByOrganizer = createdByOrganizer; mTaskFragmentOrganizerController = mAtmService.mWindowOrganizerController.mTaskFragmentOrganizerController; + mFragmentToken = fragmentToken; + mRemoteToken = new RemoteToken(this); } void setAdjacentTaskFragment(TaskFragment taskFragment) { @@ -276,6 +278,11 @@ class TaskFragment extends WindowContainer<WindowContainer> { taskFragment.mAdjacentTaskFragment = this; } + void setTaskFragmentOrganizer(ITaskFragmentOrganizer organizer, int pid) { + mTaskFragmentOrganizer = organizer; + mTaskFragmentOrganizerPid = pid; + } + TaskFragment getAdjacentTaskFragment() { return mAdjacentTaskFragment; } @@ -1981,7 +1988,6 @@ class TaskFragment extends WindowContainer<WindowContainer> { } } - // TODO(b/190433129) call when TaskFragment is removed from WCT#deleteTaskFragment private void sendTaskFragmentVanished() { if (mTaskFragmentOrganizer != null) { mTaskFragmentOrganizerController.onTaskFragmentVanished(mTaskFragmentOrganizer, this); @@ -1993,13 +1999,23 @@ class TaskFragment extends WindowContainer<WindowContainer> { * called from {@link Task}. */ TaskFragmentInfo getTaskFragmentInfo() { + List<IBinder> childActivities = new ArrayList<>(); + for (int i = 0; i < getChildCount(); i++) { + WindowContainer wc = getChildAt(i); + if (mTaskFragmentOrganizerPid != ActivityRecord.INVALID_PID + && wc.asActivityRecord() != null + && wc.asActivityRecord().getPid() == mTaskFragmentOrganizerPid) { + // Only includes Activities that belong to the organizer process for security. + childActivities.add(wc.asActivityRecord().appToken); + } + } return new TaskFragmentInfo( mFragmentToken, - mInitialComponentName, mRemoteToken.toWindowContainerToken(), getConfiguration(), getChildCount() == 0, - isVisible()); + isVisible(), + childActivities); } @Nullable @@ -2007,6 +2023,12 @@ class TaskFragment extends WindowContainer<WindowContainer> { return mFragmentToken; } + @Nullable + @VisibleForTesting + ITaskFragmentOrganizer getTaskFragmentOrganizer() { + return mTaskFragmentOrganizer; + } + /** Clear {@link #mLastPausedActivity} for all {@link TaskFragment} children */ void clearLastPausedActivity() { forAllTaskFragments(taskFragment -> taskFragment.mLastPausedActivity = null); @@ -2026,6 +2048,17 @@ class TaskFragment extends WindowContainer<WindowContainer> { mMinHeight = minHeight; } + @Override + void removeImmediately() { + if (mRemoving) { + return; + } + mRemoving = true; + super.removeImmediately(); + sendTaskFragmentVanished(); + mRemoving = false; + } + boolean dump(String prefix, FileDescriptor fd, PrintWriter pw, boolean dumpAll, boolean dumpClient, String dumpPackage, final boolean needSep, Runnable header) { boolean printed = false; diff --git a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java index 31175b7e976c..56d29dee7b45 100644 --- a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java +++ b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java @@ -24,7 +24,7 @@ import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; import android.util.ArrayMap; -import android.util.ArraySet; +import android.util.Slog; import android.view.SurfaceControl; import android.window.ITaskFragmentOrganizer; import android.window.ITaskFragmentOrganizerController; @@ -33,8 +33,8 @@ import android.window.TaskFragmentInfo; import com.android.internal.protolog.common.ProtoLog; +import java.util.ArrayList; import java.util.Map; -import java.util.Set; import java.util.WeakHashMap; /** @@ -45,104 +45,112 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr private final ActivityTaskManagerService mAtmService; private final WindowManagerGlobalLock mGlobalLock; - private final Set<ITaskFragmentOrganizer> mOrganizers = new ArraySet<>(); - private final Map<ITaskFragmentOrganizer, DeathRecipient> mDeathRecipients = new ArrayMap<>(); private final Map<TaskFragment, TaskFragmentInfo> mLastSentTaskFragmentInfos = new WeakHashMap<>(); private final Map<TaskFragment, Configuration> mLastSentTaskFragmentParentConfigs = new WeakHashMap<>(); + /** + * A Map which manages the relationship between + * {@link ITaskFragmentOrganizer} and {@link TaskFragmentOrganizerState} + */ + private final ArrayMap<IBinder, TaskFragmentController> mTaskFragmentOrganizerControllers = + new ArrayMap<>(); + + TaskFragmentOrganizerController(ActivityTaskManagerService atm) { + mAtmService = atm; + mGlobalLock = atm.mGlobalLock; + } - private class DeathRecipient implements IBinder.DeathRecipient { - final ITaskFragmentOrganizer mOrganizer; + /** + * A class to manage {@link ITaskFragmentOrganizer} and its organized + * {@link TaskFragment TaskFragments}. + */ + private class TaskFragmentController implements IBinder.DeathRecipient { + private final ArrayList<TaskFragment> mOrganizedTaskFragments = new ArrayList<>(); + private final ITaskFragmentOrganizer mOrganizer; - DeathRecipient(ITaskFragmentOrganizer organizer) { + TaskFragmentController(ITaskFragmentOrganizer organizer) { mOrganizer = organizer; + try { + mOrganizer.asBinder().linkToDeath(this, 0 /*flags*/); + } catch (RemoteException e) { + Slog.e(TAG, "TaskFragmentOrganizer failed to register death recipient"); + } } @Override public void binderDied() { - removeOrganizer(mOrganizer); + synchronized (mGlobalLock) { + removeOrganizer(mOrganizer); + } } - } - TaskFragmentOrganizerController(ActivityTaskManagerService atm) { - mAtmService = atm; - mGlobalLock = atm.mGlobalLock; + void addTaskFragment(TaskFragment taskFragment) { + if (!mOrganizedTaskFragments.contains(taskFragment)) { + mOrganizedTaskFragments.add(taskFragment); + } + } + + void removeTaskFragment(TaskFragment taskFragment) { + mOrganizedTaskFragments.remove(taskFragment); + } + + void dispose() { + mOrganizedTaskFragments.forEach(TaskFragment::removeImmediately); + mOrganizedTaskFragments.clear(); + mOrganizer.asBinder().unlinkToDeath(this, 0 /*flags*/); + } } @Override public void registerOrganizer(ITaskFragmentOrganizer organizer) { final int pid = Binder.getCallingPid(); final long uid = Binder.getCallingUid(); - final long origId = Binder.clearCallingIdentity(); - try { - synchronized (mGlobalLock) { - ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, - "Register task fragment organizer=%s uid=%d pid=%d", - organizer.asBinder(), uid, pid); - if (mOrganizers.contains(organizer)) { - throw new IllegalStateException( - "Replacing existing organizer currently unsupported"); - } - - final DeathRecipient dr = new DeathRecipient(organizer); - try { - organizer.asBinder().linkToDeath(dr, 0); - } catch (RemoteException e) { - // Oh well... - } - - mOrganizers.add(organizer); - mDeathRecipients.put(organizer, dr); + synchronized (mGlobalLock) { + ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, + "Register task fragment organizer=%s uid=%d pid=%d", + organizer.asBinder(), uid, pid); + if (mTaskFragmentOrganizerControllers.containsKey(organizer.asBinder())) { + throw new IllegalStateException( + "Replacing existing organizer currently unsupported"); } - } finally { - Binder.restoreCallingIdentity(origId); + mTaskFragmentOrganizerControllers.put(organizer.asBinder(), + new TaskFragmentController(organizer)); } } @Override public void unregisterOrganizer(ITaskFragmentOrganizer organizer) { + validateAndGetController(organizer); final int pid = Binder.getCallingPid(); final long uid = Binder.getCallingUid(); - final long origId = Binder.clearCallingIdentity(); - try { - synchronized (mGlobalLock) { - ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, - "Unregister task fragment organizer=%s uid=%d pid=%d", - organizer.asBinder(), uid, pid); - if (!mOrganizers.contains(organizer)) { - throw new IllegalStateException( - "The task fragment organizer hasn't been registered."); - } - - final DeathRecipient dr = mDeathRecipients.get(organizer); - organizer.asBinder().unlinkToDeath(dr, 0); - - removeOrganizer(organizer); - } - } finally { - Binder.restoreCallingIdentity(origId); + synchronized (mGlobalLock) { + ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, + "Unregister task fragment organizer=%s uid=%d pid=%d", + organizer.asBinder(), uid, pid); + removeOrganizer(organizer); } } void onTaskFragmentAppeared(ITaskFragmentOrganizer organizer, TaskFragment tf) { - validateOrganizer(organizer); + final TaskFragmentController controller = validateAndGetController(organizer); ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "TaskFragment appeared name=%s", tf.getName()); final TaskFragmentInfo info = tf.getTaskFragmentInfo(); final SurfaceControl outSurfaceControl = new SurfaceControl(tf.getSurfaceControl(), "TaskFragmentOrganizerController.onTaskFragmentInfoAppeared"); + controller.addTaskFragment(tf); try { organizer.onTaskFragmentAppeared( new TaskFragmentAppearedInfo(info, outSurfaceControl)); mLastSentTaskFragmentInfos.put(tf, info); } catch (RemoteException e) { - // Oh well... + Slog.e(TAG, "Exception sending onTaskFragmentAppeared callback", e); } } void onTaskFragmentInfoChanged(ITaskFragmentOrganizer organizer, TaskFragment tf) { - validateOrganizer(organizer); + validateAndGetController(organizer); // Check if the info is different from the last reported info. final TaskFragmentInfo info = tf.getTaskFragmentInfo(); @@ -157,25 +165,26 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr organizer.onTaskFragmentInfoChanged(tf.getTaskFragmentInfo()); mLastSentTaskFragmentInfos.put(tf, info); } catch (RemoteException e) { - // Oh well... + Slog.e(TAG, "Exception sending onTaskFragmentInfoChanged callback", e); } } void onTaskFragmentVanished(ITaskFragmentOrganizer organizer, TaskFragment tf) { - validateOrganizer(organizer); + final TaskFragmentController controller = validateAndGetController(organizer); ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "TaskFragment vanished name=%s", tf.getName()); try { organizer.onTaskFragmentVanished(tf.getTaskFragmentInfo()); } catch (RemoteException e) { - // Oh well... + Slog.e(TAG, "Exception sending onTaskFragmentVanished callback", e); } mLastSentTaskFragmentInfos.remove(tf); mLastSentTaskFragmentParentConfigs.remove(tf); + controller.removeTaskFragment(tf); } void onTaskFragmentParentInfoChanged(ITaskFragmentOrganizer organizer, TaskFragment tf) { - validateOrganizer(organizer); + validateAndGetController(organizer); // Check if the parent info is different from the last reported parent info. if (tf.getParent() == null || tf.getParent().asTask() == null) { @@ -194,18 +203,17 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr tf.getName(), parent.mTaskId); try { organizer.onTaskFragmentParentInfoChanged(tf.getFragmentToken(), parentConfig); - mLastSentTaskFragmentParentConfigs.put(tf, parentConfig); + mLastSentTaskFragmentParentConfigs.put(tf, new Configuration(parentConfig)); } catch (RemoteException e) { - // Oh well... + Slog.e(TAG, "Exception sending onTaskFragmentParentInfoChanged callback", e); } } private void removeOrganizer(ITaskFragmentOrganizer organizer) { - synchronized (mGlobalLock) { - mOrganizers.remove(organizer); - mDeathRecipients.remove(organizer); - } - // TODO(b/190432728) move child activities of organized TaskFragment to leaf Task + final TaskFragmentController controller = validateAndGetController(organizer); + // remove all of the children of the organized TaskFragment + controller.dispose(); + mTaskFragmentOrganizerControllers.remove(organizer.asBinder()); } /** @@ -214,10 +222,13 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr * we wouldn't register {@link DeathRecipient} for the organizer, and might not remove the * {@link TaskFragment} after the organizer process died. */ - private void validateOrganizer(ITaskFragmentOrganizer organizer) { - if (!mOrganizers.contains(organizer)) { + private TaskFragmentController validateAndGetController(ITaskFragmentOrganizer organizer) { + final TaskFragmentController controller = + mTaskFragmentOrganizerControllers.get(organizer.asBinder()); + if (controller == null) { throw new IllegalArgumentException( "TaskFragmentOrganizer has not been registered. Organizer=" + organizer); } + return controller; } } diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java index a2bdad8a64fb..a507abdae8a2 100644 --- a/services/core/java/com/android/server/wm/TaskOrganizerController.java +++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java @@ -930,6 +930,34 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { } } + @Override + public void restartTaskTopActivityProcessIfVisible(WindowContainerToken token) { + enforceTaskPermission("restartTopActivityProcessIfVisible()"); + final long origId = Binder.clearCallingIdentity(); + try { + synchronized (mGlobalLock) { + final WindowContainer wc = WindowContainer.fromBinder(token.asBinder()); + if (wc == null) { + Slog.w(TAG, "Could not resolve window from token"); + return; + } + final Task task = wc.asTask(); + if (task == null) { + Slog.w(TAG, "Could not resolve task from token"); + return; + } + ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, + "Restart top activity process of Task taskId=%d", task.mTaskId); + final ActivityRecord activity = task.getTopNonFinishingActivity(); + if (activity != null) { + activity.restartProcessIfVisible(); + } + } + } finally { + Binder.restoreCallingIdentity(origId); + } + } + public boolean handleInterceptBackPressedOnTaskRoot(Task task) { if (task == null || !task.isOrganized() || !mInterceptBackPressedOnRootTasks.contains(task.mTaskId)) { diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index ff9cc2cacd58..90e607337b7a 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -305,17 +305,27 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe final ActivityRecord ar = mParticipants.valueAt(i).asActivityRecord(); if (ar != null) { if (!ar.isVisibleRequested()) { - // If activity is capable of entering PiP, give it a chance to enter it now. + boolean commitVisibility = true; if (ar.getDeferHidingClient() && ar.getTask() != null) { - mController.mAtm.mTaskSupervisor.mUserLeaving = true; - ar.getTaskFragment().startPausing(false /* uiSleeping */, - null /* resuming */, "finishTransition"); - mController.mAtm.mTaskSupervisor.mUserLeaving = false; + if (ar.pictureInPictureArgs != null + && ar.pictureInPictureArgs.isAutoEnterEnabled()) { + mController.mAtm.enterPictureInPictureMode(ar, ar.pictureInPictureArgs); + // Avoid commit visibility to false here, or else we will get a sudden + // "flash" / surface going invisible for a split second. + commitVisibility = false; + } else { + mController.mAtm.mTaskSupervisor.mUserLeaving = true; + ar.getTaskFragment().startPausing(false /* uiSleeping */, + null /* resuming */, "finishTransition"); + mController.mAtm.mTaskSupervisor.mUserLeaving = false; + } + } + if (commitVisibility) { + ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, + " Commit activity becoming invisible: %s", ar); + ar.commitVisibility(false /* visible */, false /* performLayout */); + activitiesWentInvisible = true; } - ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, - " Commit activity becoming invisible: %s", ar); - ar.commitVisibility(false /* visible */, false /* performLayout */); - activitiesWentInvisible = true; } if (mChanges.get(ar).mVisible != ar.isVisibleRequested()) { // Legacy dispatch relies on this (for now). @@ -799,6 +809,8 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe if (reportIfNotTop(wc)) { tmpList.add(wc); } + // Wallpaper must be the top (regardless of how nested it is in DisplayAreas). + boolean skipIntermediateReports = isWallpaper(wc); for (WindowContainer p = wc.getParent(); p != null; p = p.getParent()) { if (!p.isAttached() || !changes.get(p).hasChanged(p)) { // Again, we're skipping no-ops @@ -807,7 +819,9 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe if (participants.contains(p)) { topParent = p; break; - } else if (reportIfNotTop(p)) { + } else if (isWallpaper(p)) { + skipIntermediateReports = true; + } else if (reportIfNotTop(p) && !skipIntermediateReports) { tmpList.add(p); } } @@ -893,17 +907,11 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe } // Find the top-most shared ancestor of app targets - WindowContainer ancestor = null; - for (int i = appTargets.size() - 1; i >= 0; --i) { - final WindowContainer wc = appTargets.valueAt(i); - ancestor = wc; - break; - } - if (ancestor == null) { + if (appTargets.isEmpty()) { out.setRootLeash(new SurfaceControl(), 0, 0); return out; } - ancestor = ancestor.getParent(); + WindowContainer ancestor = appTargets.valueAt(appTargets.size() - 1).getParent(); // Go up ancestor parent chain until all targets are descendants. ancestorLoop: diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 43a016d22fa5..53e02e5395a5 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -2720,8 +2720,8 @@ public class WindowManagerService extends IWindowManager.Stub } @Override - public boolean attachWindowContextToDisplayArea(IBinder clientToken, int type, int displayId, - Bundle options) { + public Configuration attachWindowContextToDisplayArea(IBinder clientToken, int + type, int displayId, Bundle options) { final boolean callerCanManageAppTokens = checkCallingPermission(MANAGE_APP_TOKENS, "attachWindowContextToDisplayArea", false /* printLog */); final int callingUid = Binder.getCallingUid(); @@ -2732,15 +2732,17 @@ public class WindowManagerService extends IWindowManager.Stub if (dc == null) { ProtoLog.w(WM_ERROR, "attachWindowContextToDisplayArea: trying to attach" + " to a non-existing display:%d", displayId); - return false; + return null; } // TODO(b/155340867): Investigate if we still need roundedCornerOverlay after // the feature b/155340867 is completed. final DisplayArea da = dc.findAreaForWindowType(type, options, callerCanManageAppTokens, false /* roundedCornerOverlay */); + // TODO(b/190019118): Avoid to send onConfigurationChanged because it has been done + // in return value of attachWindowContextToDisplayArea. mWindowContextListenerController.registerWindowContainerListener(clientToken, da, callingUid, type, options); - return true; + return da.getConfiguration(); } } finally { Binder.restoreCallingIdentity(origId); @@ -8183,11 +8185,11 @@ public class WindowManagerService extends IWindowManager.Stub displayContent.getParent().positionChildAt(WindowContainer.POSITION_TOP, displayContent, true /* includingParents */); } - handleTaskFocusChange(touchedWindow.getTask()); + handleTaskFocusChange(touchedWindow.getTask(), touchedWindow.mActivityRecord); } @VisibleForTesting - void handleTaskFocusChange(Task task) { + void handleTaskFocusChange(Task task, ActivityRecord touchedActivity) { if (task == null) { return; } @@ -8206,7 +8208,7 @@ public class WindowManagerService extends IWindowManager.Stub } } - mAtmService.setFocusedTask(task.mTaskId); + mAtmService.setFocusedTask(task.mTaskId, touchedActivity); } /** diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java index 3d36cc517e98..8dae839051fa 100644 --- a/services/core/java/com/android/server/wm/WindowOrganizerController.java +++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java @@ -16,6 +16,7 @@ package com.android.server.wm; +import static android.Manifest.permission.START_TASKS_FROM_RECENTS; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT; @@ -48,6 +49,7 @@ import android.os.Bundle; import android.os.IBinder; import android.os.Parcel; import android.os.RemoteException; +import android.util.ArrayMap; import android.util.ArraySet; import android.util.Slog; import android.view.SurfaceControl; @@ -106,6 +108,11 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub final TaskFragmentOrganizerController mTaskFragmentOrganizerController; final TransitionController mTransitionController; + /** + * A Map which manages the relationship between + * {@link TaskFragmentCreationParams.mFragmentToken fragmentToken} and {@link TaskFragment} + */ + private final ArrayMap<IBinder, TaskFragment> mLaunchTaskFragments = new ArrayMap<>(); WindowOrganizerController(ActivityTaskManagerService atm) { mService = atm; @@ -136,10 +143,11 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub if (t == null) { throw new IllegalArgumentException("Null transaction passed to applySyncTransaction"); } + final CallerInfo caller = new CallerInfo(); final long ident = Binder.clearCallingIdentity(); try { synchronized (mGlobalLock) { - applyTransaction(t, -1 /*syncId*/, null /*transition*/); + applyTransaction(t, -1 /*syncId*/, null /*transition*/, caller); } } finally { Binder.restoreCallingIdentity(ident); @@ -153,6 +161,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub if (t == null) { throw new IllegalArgumentException("Null transaction passed to applySyncTransaction"); } + final CallerInfo caller = new CallerInfo(); final long ident = Binder.clearCallingIdentity(); try { synchronized (mGlobalLock) { @@ -172,7 +181,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub if (callback != null) { syncId = startSyncWithOrganizer(callback); } - applyTransaction(t, syncId, null /*transition*/); + applyTransaction(t, syncId, null /*transition*/, caller); if (syncId >= 0) { setSyncReady(syncId); } @@ -187,6 +196,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub public IBinder startTransition(int type, @Nullable IBinder transitionToken, @Nullable WindowContainerTransaction t) { enforceTaskPermission("startTransition()"); + final CallerInfo caller = new CallerInfo(); final long ident = Binder.clearCallingIdentity(); try { synchronized (mGlobalLock) { @@ -206,7 +216,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub throw new IllegalArgumentException("Can't use legacy transitions in" + " compatibility mode with no WCT."); } - applyTransaction(t, -1 /* syncId */, null); + applyTransaction(t, -1 /* syncId */, null, caller); return null; } transition = mTransitionController.createTransition(type); @@ -215,7 +225,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub if (t == null) { t = new WindowContainerTransaction(); } - applyTransaction(t, -1 /*syncId*/, transition); + applyTransaction(t, -1 /*syncId*/, transition, caller); if (needsSetReady) { transition.setReady(); } @@ -231,6 +241,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub @Nullable WindowContainerTransaction t, @Nullable IWindowContainerTransactionCallback callback) { enforceTaskPermission("finishTransition()"); + final CallerInfo caller = new CallerInfo(); final long ident = Binder.clearCallingIdentity(); try { synchronized (mGlobalLock) { @@ -241,7 +252,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub // apply the incoming transaction before finish in case it alters the visibility // of the participants. if (t != null) { - applyTransaction(t, syncId, null /*transition*/); + applyTransaction(t, syncId, null /*transition*/, caller); } getTransitionController().finishTransition(transitionToken); if (syncId >= 0) { @@ -257,12 +268,14 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub /** * @param syncId If non-null, this will be a sync-transaction. * @param transition A transition to collect changes into. + * @param caller Info about the calling process. */ private void applyTransaction(@NonNull WindowContainerTransaction t, int syncId, - @Nullable Transition transition) { + @Nullable Transition transition, @Nullable CallerInfo caller) { int effects = 0; ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Apply window transaction, syncId=%d", syncId); mService.deferWindowLayout(); + mService.mTaskSupervisor.setDeferRootVisibilityUpdate(true /* deferUpdate */); try { if (transition != null) { // First check if we have a display rotation transition and if so, update it. @@ -313,7 +326,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub final boolean isInLockTaskMode = mService.isInLockTaskMode(); for (int i = 0; i < hopSize; ++i) { effects |= applyHierarchyOp(hops.get(i), effects, syncId, transition, - isInLockTaskMode); + isInLockTaskMode, caller); } } // Queue-up bounds-change transactions for tasks which are now organized. Do @@ -351,6 +364,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub task.setMainWindowSizeChangeTransaction(sft); } if ((effects & TRANSACT_EFFECTS_LIFECYCLE) != 0) { + mService.mTaskSupervisor.setDeferRootVisibilityUpdate(false /* deferUpdate */); // Already calls ensureActivityConfig mService.mRootWindowContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS); mService.mRootWindowContainer.resumeFocusedTasksTopActivities(); @@ -372,6 +386,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub mService.addWindowLayoutReasons(LAYOUT_REASON_CONFIG_CHANGED); } } finally { + mService.mTaskSupervisor.setDeferRootVisibilityUpdate(false /* deferUpdate */); mService.continueWindowLayout(); } } @@ -468,7 +483,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub } private int applyHierarchyOp(WindowContainerTransaction.HierarchyOp hop, int effects, - int syncId, @Nullable Transition transition, boolean isInLockTaskMode) { + int syncId, @Nullable Transition transition, boolean isInLockTaskMode, + @Nullable CallerInfo caller) { final int type = hop.getType(); switch (type) { case HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT: { @@ -549,21 +565,27 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub effects |= sanitizeAndApplyHierarchyOp(wc, hop); break; case HIERARCHY_OP_TYPE_LAUNCH_TASK: + mService.mAmInternal.enforceCallingPermission(START_TASKS_FROM_RECENTS, + "launchTask HierarchyOp"); final Bundle launchOpts = hop.getLaunchOptions(); final int taskId = launchOpts.getInt( WindowContainerTransaction.HierarchyOp.LAUNCH_KEY_TASK_ID); launchOpts.remove(WindowContainerTransaction.HierarchyOp.LAUNCH_KEY_TASK_ID); - mService.startActivityFromRecents(taskId, launchOpts); + final SafeActivityOptions safeOptions = caller != null + ? SafeActivityOptions.fromBundle(launchOpts, caller.mPid, caller.mUid) + : SafeActivityOptions.fromBundle(launchOpts); + mService.mTaskSupervisor.startActivityFromRecents(caller.mPid, caller.mUid, + taskId, safeOptions); break; case HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT: final TaskFragmentCreationParams taskFragmentCreationOptions = hop.getTaskFragmentCreationOptions(); - // TODO(b/190433129) add actual implementation on WM Core + createTaskFragment(taskFragmentCreationOptions); break; case HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT: wc = WindowContainer.fromBinder(hop.getContainer()); if (wc == null || !wc.isAttached()) { - Slog.e(TAG, "Attempt to operate on detached container: " + wc); + Slog.e(TAG, "Attempt to operate on unknown or detached container: " + wc); break; } final TaskFragment taskFragment = wc.asTaskFragment(); @@ -571,23 +593,40 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub throw new IllegalArgumentException( "Can only delete organized TaskFragment, but not Task."); } - // TODO(b/190433129) add actual implementation on WM Core + deleteTaskFragment(taskFragment); break; case HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT: fragmentToken = hop.getContainer(); + if (!mLaunchTaskFragments.containsKey(fragmentToken)) { + throw new IllegalArgumentException( + "Not allowed to operate with invalid fragment token"); + } final Intent activityIntent = hop.getActivityIntent(); final Bundle activityOptions = hop.getLaunchOptions(); - // TODO(b/190433129) add actual implementation on WM Core + mService.getActivityStartController() + .startActivityInTaskFragment(mLaunchTaskFragments.get(fragmentToken), + activityIntent, activityOptions); + // TODO(b/189385246) : report the failure back to the organizer if the activity + // start failed break; case HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT: fragmentToken = hop.getNewParent(); final ActivityRecord activity = ActivityRecord.forTokenLocked(hop.getContainer()); - // TODO(b/190433129) add actual implementation on WM Core + if (!mLaunchTaskFragments.containsKey(fragmentToken) || activity == null) { + throw new IllegalArgumentException( + "Not allowed to operate with invalid fragment token or activity."); + } + activity.reparent(mLaunchTaskFragments.get(fragmentToken), POSITION_TOP); break; case HIERARCHY_OP_TYPE_REPARENT_CHILDREN: final WindowContainer oldParent = WindowContainer.fromBinder(hop.getContainer()); final WindowContainer newParent = WindowContainer.fromBinder(hop.getNewParent()); - // TODO(b/190433129) add actual implementation on WM Core + if (oldParent == null || !oldParent.isAttached()) { + Slog.e(TAG, "Attempt to operate on unknown or detached container: " + + oldParent); + break; + } + reparentTaskFragment(oldParent, newParent); break; } return effects; @@ -866,4 +905,62 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub private void enforceTaskPermission(String func) { mService.enforceTaskPermission(func); } + + void createTaskFragment(@NonNull TaskFragmentCreationParams creationParams) { + final ActivityRecord ownerActivity = + ActivityRecord.forTokenLocked(creationParams.getOwnerToken()); + if (ownerActivity == null || ownerActivity.getTask() == null) { + // TODO(b/189385246) : report the failure back to the organizer + return; + } + // The ownerActivity has to belong to the same app as the root Activity of the target Task. + final ActivityRecord rootActivity = ownerActivity.getTask().getRootActivity(); + if (rootActivity.getUid() != ownerActivity.getUid()) { + // TODO(b/189385246) : report the failure back to the organizer + return; + } + final TaskFragment taskFragment = new TaskFragment(mService, + creationParams.getFragmentToken(), true /* createdByOrganizer */); + ownerActivity.getTask().addChild(taskFragment, POSITION_TOP); + taskFragment.setWindowingMode(creationParams.getWindowingMode()); + taskFragment.setBounds(creationParams.getInitialBounds()); + taskFragment.setTaskFragmentOrganizer( + creationParams.getOrganizer(), ownerActivity.getPid()); + mLaunchTaskFragments.put(creationParams.getFragmentToken(), taskFragment); + } + + void reparentTaskFragment(@NonNull WindowContainer oldParent, + @Nullable WindowContainer newParent) { + WindowContainer parent = newParent; + if (parent == null && oldParent.asTaskFragment() != null) { + parent = oldParent.asTaskFragment().getTask(); + } + if (parent == null) { + // TODO(b/189385246) : report the failure back to the organizer + return; + } + while (oldParent.hasChild()) { + oldParent.getChildAt(0).reparent(parent, POSITION_TOP); + } + } + + void deleteTaskFragment(@NonNull TaskFragment taskFragment) { + final int index = mLaunchTaskFragments.indexOfValue(taskFragment); + if (index < 0) { + throw new IllegalArgumentException( + "Not allowed to operate with invalid taskFragment"); + } + mLaunchTaskFragments.removeAt(index); + taskFragment.removeImmediately(); + } + + static class CallerInfo { + final int mPid; + final int mUid; + + CallerInfo() { + mPid = Binder.getCallingPid(); + mUid = Binder.getCallingUid(); + } + } } diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java index 0ca6dc6daf4a..65b065ab8eab 100644 --- a/services/core/java/com/android/server/wm/WindowProcessController.java +++ b/services/core/java/com/android/server/wm/WindowProcessController.java @@ -75,6 +75,7 @@ import com.android.server.wm.ActivityTaskManagerService.HotPath; import java.io.IOException; import java.io.PrintWriter; +import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; @@ -219,6 +220,10 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio /** Whether our process is currently running a {@link IRemoteAnimationRunner} */ private boolean mRunningRemoteAnimation; + /** List of "chained" processes that are running remote animations for this process */ + private final ArrayList<WeakReference<WindowProcessController>> mRemoteAnimationDelegates = + new ArrayList<>(); + // The bits used for mActivityStateFlags. private static final int ACTIVITY_STATE_FLAG_IS_VISIBLE = 1 << 16; private static final int ACTIVITY_STATE_FLAG_IS_PAUSING_OR_PAUSED = 1 << 17; @@ -812,7 +817,9 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio void updateNightModeForAllActivities(int nightMode) { for (int i = mActivities.size() - 1; i >= 0; --i) { final ActivityRecord r = mActivities.get(i); - r.setOverrideNightMode(nightMode); + if (r.setOverrideNightMode(nightMode) && r.mVisibleRequested) { + r.ensureActivityConfiguration(0 /* globalChanges */, true /* preserveWindow */); + } } } @@ -1594,11 +1601,38 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio updateRunningRemoteOrRecentsAnimation(); } + /** + * Marks another process as a "delegate" animator. This means that process is doing some part + * of a remote animation on behalf of this process. + */ + void addRemoteAnimationDelegate(WindowProcessController delegate) { + if (!isRunningRemoteTransition()) { + throw new IllegalStateException("Can't add a delegate to a process which isn't itself" + + " running a remote animation"); + } + mRemoteAnimationDelegates.add(new WeakReference<>(delegate)); + } + void updateRunningRemoteOrRecentsAnimation() { + if (!isRunningRemoteTransition()) { + // Clean-up any delegates + for (int i = 0; i < mRemoteAnimationDelegates.size(); ++i) { + final WindowProcessController delegate = mRemoteAnimationDelegates.get(i).get(); + if (delegate == null) continue; + delegate.setRunningRemoteAnimation(false); + delegate.setRunningRecentsAnimation(false); + } + mRemoteAnimationDelegates.clear(); + } + // Posting on handler so WM lock isn't held when we call into AM. mAtm.mH.sendMessage(PooledLambda.obtainMessage( WindowProcessListener::setRunningRemoteAnimation, mListener, - mRunningRecentsAnimation || mRunningRemoteAnimation)); + isRunningRemoteTransition())); + } + + boolean isRunningRemoteTransition() { + return mRunningRecentsAnimation || mRunningRemoteAnimation; } /** Adjusts scheduling group for animation. This method MUST NOT be called inside WM lock. */ diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index ee8426eb9d25..3abe45527004 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -875,6 +875,15 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } /** + * Returns all the requested visibilities. + * + * @return an {@link InsetsState} as the requested visibilities. + */ + InsetsState getRequestedState() { + return mRequestedInsetsState; + } + + /** * @see #getRequestedVisibility(int) */ void updateRequestedVisibility(InsetsState state) { @@ -1729,6 +1738,10 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return mActivityRecord != null ? mActivityRecord.getTask() : null; } + @Nullable TaskFragment getTaskFragment() { + return mActivityRecord != null ? mActivityRecord.getTaskFragment() : null; + } + @Nullable Task getRootTask() { final Task task = getTask(); if (task != null) { @@ -2390,6 +2403,12 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP @Override void removeImmediately() { + if (!mRemoved) { + // Destroy surface before super call. The general pattern is that the children need + // to be removed before the parent (so that the sync-engine tracking works). Since + // WindowStateAnimator is a "virtual" child, we have to do it manually here. + mWinAnimator.destroySurfaceLocked(getSyncTransaction()); + } super.removeImmediately(); if (mRemoved) { @@ -2431,8 +2450,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP disposeInputChannel(); - mWinAnimator.destroySurfaceLocked(mTmpTransaction); - mTmpTransaction.apply(); mSession.windowRemovedLocked(); try { mClient.asBinder().unlinkToDeath(mDeathRecipient, 0); @@ -2908,9 +2925,14 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // means we need to intercept touches outside of that window. The dim layer // user associated with the window (task or root task) will give us the good // bounds, as they would be used to display the dim layer. - final Task task = getTask(); - if (task != null) { - task.getDimBounds(mTmpRect); + final TaskFragment taskFragment = getTaskFragment(); + if (taskFragment != null) { + final Task task = taskFragment.asTask(); + if (task != null) { + task.getDimBounds(mTmpRect); + } else { + mTmpRect.set(taskFragment.getBounds()); + } } else if (getRootTask() != null) { getRootTask().getDimBounds(mTmpRect); } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index e553075580c4..e9babceb87c6 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -14991,9 +14991,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } private void setNetworkLoggingActiveInternal(boolean active) { - final boolean[] shouldSendNotification = new boolean[] {false}; - synchronized (getLockObject()) { - mInjector.binderWithCleanCallingIdentity(() -> { + mInjector.binderWithCleanCallingIdentity(() -> { + boolean shouldSendNotification = false; + synchronized (getLockObject()) { if (active) { if (mNetworkLogger == null) { final int affectedUserId = getNetworkLoggingAffectedUser(); @@ -15008,7 +15008,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { + " service not being available yet."); } maybePauseDeviceWideLoggingLocked(); - shouldSendNotification[0] = shouldSendNetworkLoggingNotificationLocked(); + shouldSendNotification = shouldSendNetworkLoggingNotificationLocked(); } else { if (mNetworkLogger != null && !mNetworkLogger.stopNetworkLogging()) { Slogf.wtf(LOG_TAG, "Network logging could not be stopped due to the logging" @@ -15016,15 +15016,15 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } mNetworkLogger = null; } - }); - } - if (active) { - if (shouldSendNotification[0]) { - sendNetworkLoggingNotification(); } - } else { - mInjector.getNotificationManager().cancel(SystemMessage.NOTE_NETWORK_LOGGING); - } + if (active) { + if (shouldSendNotification) { + sendNetworkLoggingNotification(); + } + } else { + mInjector.getNotificationManager().cancel(SystemMessage.NOTE_NETWORK_LOGGING); + } + }); } private @UserIdInt int getNetworkLoggingAffectedUser() { @@ -17557,9 +17557,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } final boolean usbEnabled; synchronized (getLockObject()) { - final ActiveAdmin admin = getDeviceOwnerOrProfileOwnerOfOrganizationOwnedDeviceLocked( - UserHandle.USER_SYSTEM); - usbEnabled = admin != null && admin.mUsbDataSignalingEnabled; + usbEnabled = isUsbDataSignalingEnabledInternalLocked(); } if (!mInjector.binderWithCleanCallingIdentity( () -> mInjector.getUsbManager().enableUsbDataSignal(usbEnabled))) { diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index d487483cfb56..81995a79d9d8 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -377,6 +377,8 @@ public final class SystemServer implements Dumpable { "com.android.server.connectivity.IpConnectivityMetrics"; private static final String MEDIA_COMMUNICATION_SERVICE_CLASS = "com.android.server.media.MediaCommunicationService"; + private static final String APP_COMPAT_OVERRIDES_SERVICE_CLASS = + "com.android.server.compat.overrides.AppCompatOverridesService$Lifecycle"; private static final String ROLE_SERVICE_CLASS = "com.android.role.RoleService"; private static final String GAME_MANAGER_SERVICE_CLASS = @@ -552,6 +554,7 @@ public final class SystemServer implements Dumpable { if (maxFd > enableThreshold) { // Do a manual GC to clean up fds that are hanging around as garbage. System.gc(); + System.runFinalization(); maxFd = getMaxFd(); } @@ -2649,6 +2652,10 @@ public final class SystemServer implements Dumpable { mSystemServiceManager.startService(MEDIA_COMMUNICATION_SERVICE_CLASS); t.traceEnd(); + t.traceBegin("AppCompatOverridesService"); + mSystemServiceManager.startService(APP_COMPAT_OVERRIDES_SERVICE_CLASS); + t.traceEnd(); + ConcurrentUtils.waitForFutureNoInterrupt(mBlobStoreServiceStart, START_BLOB_STORE_SERVICE); diff --git a/services/musicrecognition/java/com/android/server/musicrecognition/MusicRecognitionManagerPerUserService.java b/services/musicrecognition/java/com/android/server/musicrecognition/MusicRecognitionManagerPerUserService.java index 4c5bbebdfd45..2cd20c56b5e1 100644 --- a/services/musicrecognition/java/com/android/server/musicrecognition/MusicRecognitionManagerPerUserService.java +++ b/services/musicrecognition/java/com/android/server/musicrecognition/MusicRecognitionManagerPerUserService.java @@ -208,6 +208,24 @@ public final class MusicRecognitionManagerPerUserService extends @NonNull RecognitionRequest recognitionRequest, IMusicRecognitionManagerCallback clientCallback, ParcelFileDescriptor audioSink) { + int maxAudioLengthSeconds = Math.min(recognitionRequest.getMaxAudioLengthSeconds(), + MAX_STREAMING_SECONDS); + if (maxAudioLengthSeconds <= 0) { + // TODO(b/192992319): A request to stream 0s of audio can be used to initialize the + // music recognition service implementation, hence not reporting an error here. + // The TODO for Android T is to move this functionality into an init() API call. + Slog.i(TAG, "No audio requested. Closing stream."); + try { + audioSink.close(); + clientCallback.onAudioStreamClosed(); + } catch (IOException e) { + Slog.e(TAG, "Problem closing stream.", e); + } catch (RemoteException ignored) { + // Ignored. + } + return; + } + try { startRecordAudioOp(attributionTag); } catch (SecurityException e) { @@ -224,8 +242,6 @@ public final class MusicRecognitionManagerPerUserService extends return; } - int maxAudioLengthSeconds = Math.min(recognitionRequest.getMaxAudioLengthSeconds(), - MAX_STREAMING_SECONDS); AudioRecord audioRecord = createAudioRecord(recognitionRequest, maxAudioLengthSeconds); try (OutputStream fos = new ParcelFileDescriptor.AutoCloseOutputStream(audioSink)) { diff --git a/services/tests/mockingservicestests/src/com/android/server/appsearch/AppSearchConfigTest.java b/services/tests/mockingservicestests/src/com/android/server/appsearch/AppSearchConfigTest.java index ffb1dd9c7e78..8336663d4dd1 100644 --- a/services/tests/mockingservicestests/src/com/android/server/appsearch/AppSearchConfigTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/appsearch/AppSearchConfigTest.java @@ -54,6 +54,12 @@ public class AppSearchConfigTest { AppSearchConfig.DEFAULT_LIMIT_CONFIG_MAX_DOCUMENT_SIZE_BYTES); assertThat(appSearchConfig.getCachedLimitConfigMaxDocumentCount()).isEqualTo( AppSearchConfig.DEFAULT_LIMIT_CONFIG_MAX_DOCUMENT_COUNT); + assertThat(appSearchConfig.getCachedBytesOptimizeThreshold()).isEqualTo( + AppSearchConfig.DEFAULT_BYTES_OPTIMIZE_THRESHOLD); + assertThat(appSearchConfig.getCachedTimeOptimizeThresholdMs()).isEqualTo( + AppSearchConfig.DEFAULT_TIME_OPTIMIZE_THRESHOLD_MILLIS); + assertThat(appSearchConfig.getCachedDocCountOptimizeThreshold()).isEqualTo( + AppSearchConfig.DEFAULT_DOC_COUNT_OPTIMIZE_THRESHOLD); } @Test @@ -163,10 +169,8 @@ public class AppSearchConfigTest { /** * Tests if we fall back to {@link AppSearchConfig#DEFAULT_SAMPLING_INTERVAL} if both default - * sampling - * interval and custom value are not set in DeviceConfig, and there is some other sampling - * interval - * set. + * sampling interval and custom value are not set in DeviceConfig, and there is some other + * sampling interval set. */ @Test public void testFallbackToDefaultSamplingValue_useHardCodedDefault() { @@ -269,7 +273,7 @@ public class AppSearchConfigTest { } @Test - public void testCustomizedValue() { + public void testCustomizedValue_maxDocument() { DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH, AppSearchConfig.KEY_LIMIT_CONFIG_MAX_DOCUMENT_SIZE_BYTES, Integer.toString(2001), @@ -285,6 +289,64 @@ public class AppSearchConfigTest { } @Test + public void testCustomizedValue_optimizeThreshold() { + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH, + AppSearchConfig.KEY_BYTES_OPTIMIZE_THRESHOLD, + Integer.toString(147147), + false); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH, + AppSearchConfig.KEY_TIME_OPTIMIZE_THRESHOLD_MILLIS, + Integer.toString(258258), + false); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH, + AppSearchConfig.KEY_DOC_COUNT_OPTIMIZE_THRESHOLD, + Integer.toString(369369), + false); + + AppSearchConfig appSearchConfig = AppSearchConfig.create(DIRECT_EXECUTOR); + + assertThat(appSearchConfig.getCachedBytesOptimizeThreshold()).isEqualTo(147147); + assertThat(appSearchConfig.getCachedTimeOptimizeThresholdMs()).isEqualTo(258258); + assertThat(appSearchConfig.getCachedDocCountOptimizeThreshold()).isEqualTo(369369); + } + + @Test + public void testCustomizedValueOverride_optimizeThreshold() { + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH, + AppSearchConfig.KEY_BYTES_OPTIMIZE_THRESHOLD, + Integer.toString(147147), + false); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH, + AppSearchConfig.KEY_TIME_OPTIMIZE_THRESHOLD_MILLIS, + Integer.toString(258258), + false); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH, + AppSearchConfig.KEY_DOC_COUNT_OPTIMIZE_THRESHOLD, + Integer.toString(369369), + false); + + AppSearchConfig appSearchConfig = AppSearchConfig.create(DIRECT_EXECUTOR); + + // Override + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH, + AppSearchConfig.KEY_BYTES_OPTIMIZE_THRESHOLD, + Integer.toString(741741), + false); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH, + AppSearchConfig.KEY_TIME_OPTIMIZE_THRESHOLD_MILLIS, + Integer.toString(852852), + false); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH, + AppSearchConfig.KEY_DOC_COUNT_OPTIMIZE_THRESHOLD, + Integer.toString(963963), + false); + + assertThat(appSearchConfig.getCachedBytesOptimizeThreshold()).isEqualTo(741741); + assertThat(appSearchConfig.getCachedTimeOptimizeThresholdMs()).isEqualTo(852852); + assertThat(appSearchConfig.getCachedDocCountOptimizeThreshold()).isEqualTo(963963); + } + + @Test public void testNotUsable_afterClose() { AppSearchConfig appSearchConfig = AppSearchConfig.create(DIRECT_EXECUTOR); @@ -302,5 +364,14 @@ public class AppSearchConfigTest { Assert.assertThrows("Trying to use a closed AppSearchConfig instance.", IllegalStateException.class, () -> appSearchConfig.getCachedSamplingIntervalForPutDocumentStats()); + Assert.assertThrows("Trying to use a closed AppSearchConfig instance.", + IllegalStateException.class, + () -> appSearchConfig.getCachedBytesOptimizeThreshold()); + Assert.assertThrows("Trying to use a closed AppSearchConfig instance.", + IllegalStateException.class, + () -> appSearchConfig.getCachedTimeOptimizeThresholdMs()); + Assert.assertThrows("Trying to use a closed AppSearchConfig instance.", + IllegalStateException.class, + () -> appSearchConfig.getCachedDocCountOptimizeThreshold()); } } diff --git a/services/tests/mockingservicestests/src/com/android/server/compat/overrides/AppCompatOverridesParserTest.java b/services/tests/mockingservicestests/src/com/android/server/compat/overrides/AppCompatOverridesParserTest.java new file mode 100644 index 000000000000..bf97042d7b88 --- /dev/null +++ b/services/tests/mockingservicestests/src/com/android/server/compat/overrides/AppCompatOverridesParserTest.java @@ -0,0 +1,302 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.compat.overrides; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.when; + +import static java.util.Collections.emptySet; + +import android.app.compat.PackageOverride; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.platform.test.annotations.Presubmit; +import android.util.ArraySet; + +import androidx.test.filters.SmallTest; + +import com.android.server.compat.overrides.AppCompatOverridesParser.PackageOverrides; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import java.util.Arrays; +import java.util.Map; +import java.util.Set; + +/** + * Test class for {@link AppCompatOverridesParser}. + * + * Build/Install/Run: + * atest FrameworksMockingServicesTests:AppCompatOverridesParserTest + */ +@RunWith(MockitoJUnitRunner.class) +@SmallTest +@Presubmit +public class AppCompatOverridesParserTest { + private static final String PACKAGE_1 = "com.android.test1"; + private static final String PACKAGE_2 = "com.android.test2"; + private static final String PACKAGE_3 = "com.android.test3"; + private static final String PACKAGE_4 = "com.android.test4"; + + private AppCompatOverridesParser mParser; + + @Mock + private PackageManager mPackageManager; + + @Before + public void setUp() throws Exception { + mParser = new AppCompatOverridesParser(mPackageManager); + } + + @Test + public void parseRemoveOverrides_emptyConfig_returnsEmpty() { + Set<Long> ownedChangeIds = new ArraySet<>(Arrays.asList(123L, 456L)); + + assertThat(mParser.parseRemoveOverrides("", ownedChangeIds)).isEmpty(); + } + + @Test + public void parseRemoveOverrides_configHasWildcardNoOwnedChangeIds_returnsEmpty() { + when(mPackageManager.getInstalledApplications(anyInt())) + .thenReturn(Arrays.asList(createAppInfo(PACKAGE_1), createAppInfo(PACKAGE_2))); + + assertThat(mParser.parseRemoveOverrides("*", /* ownedChangeIds= */ emptySet())).isEmpty(); + } + + @Test + public void parseRemoveOverrides_configHasWildcard_returnsAllInstalledPackagesToAllOwnedIds() { + Set<Long> ownedChangeIds = new ArraySet<>(Arrays.asList(123L, 456L)); + when(mPackageManager.getInstalledApplications(anyInt())) + .thenReturn(Arrays.asList(createAppInfo(PACKAGE_1), createAppInfo(PACKAGE_2), + createAppInfo(PACKAGE_3))); + + Map<String, Set<Long>> result = mParser.parseRemoveOverrides("*", ownedChangeIds); + + assertThat(result).hasSize(3); + assertThat(result.get(PACKAGE_1)).containsExactly(123L, 456L); + assertThat(result.get(PACKAGE_2)).containsExactly(123L, 456L); + assertThat(result.get(PACKAGE_3)).containsExactly(123L, 456L); + } + + @Test + public void parseRemoveOverrides_configHasInvalidWildcardSymbol_returnsEmpty() { + Set<Long> ownedChangeIds = new ArraySet<>(Arrays.asList(123L, 456L)); + when(mPackageManager.getInstalledApplications(anyInt())).thenReturn( + Arrays.asList(createAppInfo(PACKAGE_1), createAppInfo(PACKAGE_2))); + + assertThat(mParser.parseRemoveOverrides("**", ownedChangeIds)).isEmpty(); + } + + @Test + public void parseRemoveOverrides_configHasSingleEntry_returnsPackageToChangeIds() { + Map<String, Set<Long>> result = mParser.parseRemoveOverrides( + PACKAGE_1 + "=12:34", /* ownedChangeIds= */ emptySet()); + + assertThat(result).hasSize(1); + assertThat(result.get(PACKAGE_1)).containsExactly(12L, 34L); + } + + @Test + public void parseRemoveOverrides_configHasMultipleEntries_returnsPackagesToChangeIds() { + Set<Long> ownedChangeIds = new ArraySet<>(Arrays.asList(12L, 34L, 56L, 78L)); + + Map<String, Set<Long>> result = mParser.parseRemoveOverrides( + PACKAGE_1 + "=12," + PACKAGE_2 + "=*," + PACKAGE_3 + "=12:56:78," + PACKAGE_4 + + "=", ownedChangeIds); + + assertThat(result).hasSize(3); + assertThat(result.get(PACKAGE_1)).containsExactly(12L); + assertThat(result.get(PACKAGE_2)).containsExactly(12L, 34L, 56L, 78L); + assertThat(result.get(PACKAGE_3)).containsExactly(12L, 56L, 78L); + } + + @Test + public void parseRemoveOverrides_configHasPackageWithWildcardNoOwnedId_returnsWithoutPackage() { + Map<String, Set<Long>> result = mParser.parseRemoveOverrides( + PACKAGE_1 + "=*," + PACKAGE_2 + "=12", /* ownedChangeIds= */ emptySet()); + + assertThat(result).hasSize(1); + assertThat(result.get(PACKAGE_2)).containsExactly(12L); + } + + @Test + public void parseRemoveOverrides_configHasInvalidKeyValueListFormat_returnsEmpty() { + Set<Long> ownedChangeIds = new ArraySet<>(Arrays.asList(12L, 34L)); + + assertThat(mParser.parseRemoveOverrides( + PACKAGE_1 + "=12," + PACKAGE_2 + ">34", ownedChangeIds)).isEmpty(); + } + + + @Test + public void parseRemoveOverrides_configHasInvalidChangeIds_returnsWithoutInvalidChangeIds() { + Map<String, Set<Long>> result = mParser.parseRemoveOverrides( + PACKAGE_1 + "=12," + PACKAGE_2 + "=12:56L:78," + PACKAGE_3 + + "=34L", /* ownedChangeIds= */ emptySet()); + + assertThat(result).hasSize(2); + assertThat(result.get(PACKAGE_1)).containsExactly(12L); + assertThat(result.get(PACKAGE_2)).containsExactly(12L, 78L); + } + + @Test + public void parseOwnedChangeIds_emptyConfig_returnsEmpty() { + assertThat(AppCompatOverridesParser.parseOwnedChangeIds("")).isEmpty(); + } + + @Test + public void parseOwnedChangeIds_configHasSingleChangeId_returnsChangeId() { + assertThat(AppCompatOverridesParser.parseOwnedChangeIds("123")).containsExactly(123L); + } + + @Test + public void parseOwnedChangeIds_configHasMultipleChangeIds_returnsChangeIds() { + assertThat(AppCompatOverridesParser.parseOwnedChangeIds("12,34,56")).containsExactly(12L, + 34L, 56L); + } + + @Test + public void parseOwnedChangeIds_configHasInvalidChangeIds_returnsWithoutInvalidChangeIds() { + // We add a valid entry before and after the invalid ones to make sure they are applied. + assertThat(AppCompatOverridesParser.parseOwnedChangeIds("12,C34,56")).containsExactly(12L, + 56L); + } + + @Test + public void parsePackageOverrides_emptyConfig_returnsEmpty() { + PackageOverrides result = AppCompatOverridesParser.parsePackageOverrides(/* configStr= */ + "", /* versionCode= */ 0, /* changeIdsToSkip= */ emptySet()); + + assertThat(result.overridesToAdd).isEmpty(); + assertThat(result.overridesToRemove).isEmpty(); + } + + @Test + public void parsePackageOverrides_configWithSingleOverride_returnsOverride() { + PackageOverrides result = AppCompatOverridesParser.parsePackageOverrides(/* configStr= */ + "123:::true", /* versionCode= */ 5, /* changeIdsToSkip= */ emptySet()); + + assertThat(result.overridesToAdd).hasSize(1); + assertThat(result.overridesToAdd.get(123L)).isEqualTo( + new PackageOverride.Builder().setEnabled(true).build()); + } + + @Test + public void parsePackageOverrides_configWithMultipleOverridesToAdd_returnsOverrides() { + PackageOverrides result = AppCompatOverridesParser.parsePackageOverrides(/* configStr= */ + "910:3:4:false,78:10::false,12:::false,34:1:2:true,34:10::true,56::2:true," + + "56:3:4:false,34:4:8:true,78:6:7:true,910:5::true,1112::5:true," + + "56:6::true,1112:6:7:false", /* versionCode= */ + 5, /* changeIdsToSkip= */ emptySet()); + + assertThat(result.overridesToAdd).hasSize(6); + assertThat(result.overridesToAdd.get(12L)).isEqualTo( + new PackageOverride.Builder().setEnabled(false).build()); + assertThat(result.overridesToAdd.get(34L)).isEqualTo( + new PackageOverride.Builder().setMinVersionCode(4).setMaxVersionCode(8).setEnabled( + true).build()); + assertThat(result.overridesToAdd.get(56L)).isEqualTo( + new PackageOverride.Builder().setMinVersionCode(3).setMaxVersionCode(4).setEnabled( + false).build()); + assertThat(result.overridesToAdd.get(78L)).isEqualTo( + new PackageOverride.Builder().setMinVersionCode(6).setMaxVersionCode(7).setEnabled( + true).build()); + assertThat(result.overridesToAdd.get(910L)).isEqualTo( + new PackageOverride.Builder().setMinVersionCode(5).setEnabled(true).build()); + assertThat(result.overridesToAdd.get(1112L)).isEqualTo( + new PackageOverride.Builder().setMaxVersionCode(5).setEnabled(true).build()); + assertThat(result.overridesToRemove).isEmpty(); + } + + @Test + public void parsePackageOverrides_configWithMultipleOverridesToRemove_returnsOverrides() { + PackageOverrides result = AppCompatOverridesParser.parsePackageOverrides(/* configStr= */ + "12:::,34:1:2:", /* versionCode= */ 5, /* changeIdsToSkip= */ emptySet()); + + assertThat(result.overridesToRemove).containsExactly(12L, 34L); + assertThat(result.overridesToAdd).isEmpty(); + } + + @Test + public void parsePackageOverrides_configWithBothOverridesToAddAndRemove_returnsOverrides() { + // Note that change 56 is both added and removed, therefore it will only be removed. + PackageOverrides result = AppCompatOverridesParser.parsePackageOverrides(/* configStr= */ + "56:::,12:::true,34:::,56:3:7:true", /* versionCode= */ 5, /* changeIdsToSkip= */ + emptySet()); + + assertThat(result.overridesToAdd).hasSize(1); + assertThat(result.overridesToAdd.get(12L)).isEqualTo( + new PackageOverride.Builder().setEnabled(true).build()); + assertThat(result.overridesToRemove).containsExactly(34L, 56L); + } + + @Test + public void parsePackageOverrides_changeIdsToSkipSpecified_returnsWithoutChangeIdsToSkip() { + ArraySet<Long> changeIdsToSkip = new ArraySet<>(); + changeIdsToSkip.add(34L); + changeIdsToSkip.add(56L); + changeIdsToSkip.add(910L); + PackageOverrides result = AppCompatOverridesParser.parsePackageOverrides(/* configStr= */ + "12:::true,34:::,56:3:7:true,78:::", /* versionCode= */ 5, changeIdsToSkip); + + assertThat(result.overridesToAdd).hasSize(1); + assertThat(result.overridesToAdd.get(12L)).isEqualTo( + new PackageOverride.Builder().setEnabled(true).build()); + assertThat(result.overridesToRemove).containsExactly(78L); + } + + @Test + public void parsePackageOverrides_changeIdsToSkipContainsAllIds_returnsEmpty() { + ArraySet<Long> changeIdsToSkip = new ArraySet<>(); + changeIdsToSkip.add(12L); + changeIdsToSkip.add(34L); + PackageOverrides result = AppCompatOverridesParser.parsePackageOverrides(/* configStr= */ + "12:::true,34:::", /* versionCode= */ 5, changeIdsToSkip); + + assertThat(result.overridesToAdd).isEmpty(); + assertThat(result.overridesToRemove).isEmpty(); + } + + @Test + public void parsePackageOverrides_someOverridesAreInvalid_returnsWithoutInvalidOverrides() { + // We add a valid entry before and after the invalid ones to make sure they are applied. + PackageOverrides result = AppCompatOverridesParser.parsePackageOverrides(/* configStr= */ + "12:::True,56:1:2:FALSE,56:3:true,78:4:8:true:,C1:::true,910:::no," + + "1112:1:ten:true,1112:one:10:true,,1314:7:3:false,34:one:ten:", + /* versionCode= */ 5, /* changeIdsToSkip= */ emptySet()); + + assertThat(result.overridesToAdd).hasSize(2); + assertThat(result.overridesToAdd.get(12L)).isEqualTo( + new PackageOverride.Builder().setEnabled(true).build()); + assertThat(result.overridesToAdd.get(56L)).isEqualTo( + new PackageOverride.Builder().setMinVersionCode(1).setMaxVersionCode(2).setEnabled( + false).build()); + assertThat(result.overridesToRemove).containsExactly(34L); + } + + private static ApplicationInfo createAppInfo(String packageName) { + ApplicationInfo appInfo = new ApplicationInfo(); + appInfo.packageName = packageName; + return appInfo; + } +} diff --git a/services/tests/mockingservicestests/src/com/android/server/compat/overrides/AppCompatOverridesServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/compat/overrides/AppCompatOverridesServiceTest.java new file mode 100644 index 000000000000..312927206a80 --- /dev/null +++ b/services/tests/mockingservicestests/src/com/android/server/compat/overrides/AppCompatOverridesServiceTest.java @@ -0,0 +1,688 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.compat.overrides; + +import static android.content.Intent.ACTION_PACKAGE_ADDED; +import static android.content.Intent.ACTION_PACKAGE_CHANGED; +import static android.content.Intent.ACTION_PACKAGE_REMOVED; +import static android.content.Intent.ACTION_USER_SWITCHED; + +import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; +import static com.android.server.compat.overrides.AppCompatOverridesParser.FLAG_OWNED_CHANGE_IDS; +import static com.android.server.compat.overrides.AppCompatOverridesParser.FLAG_REMOVE_OVERRIDES; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.when; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.compat.PackageOverride; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.ContextWrapper; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.net.Uri; +import android.os.Handler; +import android.os.RemoteException; +import android.platform.test.annotations.Presubmit; +import android.provider.DeviceConfig; +import android.provider.DeviceConfig.Properties; + +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.SmallTest; + +import com.android.internal.compat.CompatibilityOverrideConfig; +import com.android.internal.compat.CompatibilityOverridesToRemoveConfig; +import com.android.internal.compat.IPlatformCompat; +import com.android.server.testables.TestableDeviceConfig.TestableDeviceConfigRule; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Executor; + +/** + * Test class for {@link AppCompatOverridesService}. + * + * Build/Install/Run: + * atest FrameworksMockingServicesTests:AppCompatOverridesServiceTest + */ +@RunWith(MockitoJUnitRunner.class) +@SmallTest +@Presubmit +public class AppCompatOverridesServiceTest { + private static final String NAMESPACE_1 = "namespace_1"; + private static final String NAMESPACE_2 = "namespace_2"; + private static final String NAMESPACE_3 = "namespace_3"; + private static final List<String> SUPPORTED_NAMESPACES = Arrays.asList(NAMESPACE_1, + NAMESPACE_2, NAMESPACE_3); + + private static final String PACKAGE_1 = "com.android.test1"; + private static final String PACKAGE_2 = "com.android.test2"; + private static final String PACKAGE_3 = "com.android.test3"; + private static final String PACKAGE_4 = "com.android.test4"; + private static final String PACKAGE_5 = "com.android.test5"; + + private MockContext mMockContext; + private BroadcastReceiver mPackageReceiver; + private AppCompatOverridesService mService; + + @Mock + private PackageManager mPackageManager; + @Mock + private IPlatformCompat mPlatformCompat; + + @Captor + private ArgumentCaptor<CompatibilityOverrideConfig> mOverridesToAddConfigCaptor; + @Captor + private ArgumentCaptor<CompatibilityOverridesToRemoveConfig> mOverridesToRemoveConfigCaptor; + + @Rule + public TestableDeviceConfigRule mDeviceConfigRule = new TestableDeviceConfigRule(); + + class MockContext extends ContextWrapper { + MockContext(Context base) { + super(base); + } + + @Override + public PackageManager getPackageManager() { + return mPackageManager; + } + + @Override + public Executor getMainExecutor() { + // Run on current thread + return Runnable::run; + } + + @Override + @Nullable + public Intent registerReceiverForAllUsers(@Nullable BroadcastReceiver receiver, + @NonNull IntentFilter filter, @Nullable String broadcastPermission, + @Nullable Handler scheduler) { + mPackageReceiver = receiver; + return null; + } + } + + @Before + public void setUp() throws Exception { + mMockContext = new MockContext( + InstrumentationRegistry.getInstrumentation().getTargetContext()); + mService = new AppCompatOverridesService(mMockContext, mPlatformCompat, + SUPPORTED_NAMESPACES); + mService.registerPackageReceiver(); + assertThat(mPackageReceiver).isNotNull(); + } + + @Test + public void onPropertiesChanged_removeOverridesFlagNotSet_appliesPackageOverrides() + throws Exception { + mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 3); + mockGetApplicationInfoNotInstalled(PACKAGE_2); + mockGetApplicationInfo(PACKAGE_3, /* versionCode= */ 10); + mockGetApplicationInfo(PACKAGE_4, /* versionCode= */ 1); + mockGetApplicationInfo(PACKAGE_5, /* versionCode= */ 1); + + mService.registerDeviceConfigListeners(); + DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1) + .setString(PACKAGE_1, "123:::true,456::1:false,456:2::true") + .setString(PACKAGE_2, "123:::true") + .setString(PACKAGE_3, "123:1:9:true,123:10:11:false,123:11::true,456:::") + .setString(PACKAGE_4, "") + .setString(PACKAGE_5, "123:::,789:::") + .setString(FLAG_OWNED_CHANGE_IDS, "123,456,789").build()); + + Map<Long, PackageOverride> addedOverrides; + // Package 1 + verify(mPlatformCompat).putOverridesOnReleaseBuilds(mOverridesToAddConfigCaptor.capture(), + eq(PACKAGE_1)); + verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds( + any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_1)); + addedOverrides = mOverridesToAddConfigCaptor.getValue().overrides; + assertThat(addedOverrides).hasSize(2); + assertThat(addedOverrides.get(123L)).isEqualTo( + new PackageOverride.Builder().setEnabled(true).build()); + assertThat(addedOverrides.get(456L)).isEqualTo( + new PackageOverride.Builder().setMinVersionCode(2).setEnabled(true).build()); + // Package 2 + verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds( + any(CompatibilityOverrideConfig.class), eq(PACKAGE_2)); + verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds( + any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_2)); + // Package 3 + verify(mPlatformCompat).putOverridesOnReleaseBuilds(mOverridesToAddConfigCaptor.capture(), + eq(PACKAGE_3)); + verify(mPlatformCompat).removeOverridesOnReleaseBuilds( + mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_3)); + addedOverrides = mOverridesToAddConfigCaptor.getValue().overrides; + assertThat(addedOverrides).hasSize(1); + assertThat(addedOverrides.get(123L)).isEqualTo( + new PackageOverride.Builder().setMinVersionCode(10).setMaxVersionCode( + 11).setEnabled(false).build()); + assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(456L); + // Package 4 + verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds( + any(CompatibilityOverrideConfig.class), eq(PACKAGE_4)); + verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds( + any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_4)); + // Package 5 + verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds( + any(CompatibilityOverrideConfig.class), eq(PACKAGE_5)); + verify(mPlatformCompat).removeOverridesOnReleaseBuilds( + mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_5)); + assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(123L, 789L); + } + + @Test + public void onPropertiesChanged_removeOverridesFlagSetBefore_skipsOverridesToRemove() + throws Exception { + DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1) + .setString(FLAG_REMOVE_OVERRIDES, PACKAGE_1 + "=123:456," + PACKAGE_2 + "=123") + .setString(PACKAGE_1, "123:::true") + .setString(PACKAGE_4, "123:::true").build()); + mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 0); + mockGetApplicationInfo(PACKAGE_2, /* versionCode= */ 0); + mockGetApplicationInfo(PACKAGE_3, /* versionCode= */ 0); + + mService.registerDeviceConfigListeners(); + DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1) + .setString(PACKAGE_1, "123:::true,456:::,789:::false") + .setString(PACKAGE_2, "123:::true") + .setString(PACKAGE_3, "456:::true").build()); + + // Package 1 + verify(mPlatformCompat).putOverridesOnReleaseBuilds(mOverridesToAddConfigCaptor.capture(), + eq(PACKAGE_1)); + verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds( + any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_1)); + assertThat(mOverridesToAddConfigCaptor.getValue().overrides.keySet()).containsExactly(789L); + // Package 2 + verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds( + any(CompatibilityOverrideConfig.class), eq(PACKAGE_2)); + verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds( + any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_2)); + // Package 3 + verify(mPlatformCompat).putOverridesOnReleaseBuilds(mOverridesToAddConfigCaptor.capture(), + eq(PACKAGE_3)); + verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds( + any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_3)); + assertThat(mOverridesToAddConfigCaptor.getValue().overrides.keySet()).containsExactly(456L); + // Package 4 (not applied because it hasn't changed after the listener was added) + verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds( + any(CompatibilityOverrideConfig.class), eq(PACKAGE_4)); + verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds( + any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_4)); + } + + @Test + public void onPropertiesChanged_removeOverridesFlagChangedNoPackageOverridesFlags_removesOnly() + throws Exception { + mService.registerDeviceConfigListeners(); + DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1) + .setString(FLAG_REMOVE_OVERRIDES, + PACKAGE_1 + "=123:456," + PACKAGE_2 + "=789").build()); + + // Package 1 + verify(mPlatformCompat).removeOverridesOnReleaseBuilds( + mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_1)); + assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(123L, 456L); + // Package 2 + verify(mPlatformCompat).removeOverridesOnReleaseBuilds( + mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_2)); + assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(789L); + } + + @Test + public void onPropertiesChanged_removeOverridesFlagAndSomePackageOverrideFlagsChanged_ok() + throws Exception { + DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1) + .setString(FLAG_REMOVE_OVERRIDES, PACKAGE_1 + "=123:456") + .setString(PACKAGE_1, "123:::true,456:::,789:::false") + .setString(PACKAGE_3, "456:::false,789:::true").build()); + mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 0); + mockGetApplicationInfo(PACKAGE_2, /* versionCode= */ 0); + mockGetApplicationInfo(PACKAGE_3, /* versionCode= */ 0); + + mService.registerDeviceConfigListeners(); + DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1) + .setString(FLAG_REMOVE_OVERRIDES, PACKAGE_2 + "=123," + PACKAGE_3 + "=789") + .setString(PACKAGE_2, "123:::true,456:::").build()); + + // Package 1 + verify(mPlatformCompat).putOverridesOnReleaseBuilds(mOverridesToAddConfigCaptor.capture(), + eq(PACKAGE_1)); + verify(mPlatformCompat).removeOverridesOnReleaseBuilds( + mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_1)); + assertThat(mOverridesToAddConfigCaptor.getValue().overrides.keySet()).containsExactly(123L, + 789L); + assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(456L); + // Package 2 + verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds( + any(CompatibilityOverrideConfig.class), eq(PACKAGE_2)); + verify(mPlatformCompat, times(2)).removeOverridesOnReleaseBuilds( + mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_2)); + List<CompatibilityOverridesToRemoveConfig> configs = + mOverridesToRemoveConfigCaptor.getAllValues(); + assertThat(configs.size()).isAtLeast(2); + assertThat(configs.get(configs.size() - 2).changeIds).containsExactly(123L); + assertThat(configs.get(configs.size() - 1).changeIds).containsExactly(456L); + // Package 3 + verify(mPlatformCompat).putOverridesOnReleaseBuilds(mOverridesToAddConfigCaptor.capture(), + eq(PACKAGE_3)); + verify(mPlatformCompat).removeOverridesOnReleaseBuilds( + mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_3)); + assertThat(mOverridesToAddConfigCaptor.getValue().overrides.keySet()).containsExactly(456L); + assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(789L); + } + + @Test + public void onPropertiesChanged_ownedChangeIdsFlagAndSomePackageOverrideFlagsChanged_ok() + throws Exception { + DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1) + .setString(FLAG_REMOVE_OVERRIDES, PACKAGE_1 + "=*") + .setString(FLAG_OWNED_CHANGE_IDS, "123,456") + .setString(PACKAGE_1, "123:::true") + .setString(PACKAGE_3, "456:::false").build()); + mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 0); + mockGetApplicationInfo(PACKAGE_2, /* versionCode= */ 0); + mockGetApplicationInfo(PACKAGE_3, /* versionCode= */ 0); + + mService.registerDeviceConfigListeners(); + DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1) + .setString(FLAG_OWNED_CHANGE_IDS, "123,456,789") + .setString(PACKAGE_2, "123:::true").build()); + + // Package 1 + verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds( + any(CompatibilityOverrideConfig.class), eq(PACKAGE_1)); + verify(mPlatformCompat).removeOverridesOnReleaseBuilds( + mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_1)); + assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(123L, 456L, + 789L); + // Package 2 + verify(mPlatformCompat).putOverridesOnReleaseBuilds(mOverridesToAddConfigCaptor.capture(), + eq(PACKAGE_2)); + verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds( + any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_2)); + assertThat(mOverridesToAddConfigCaptor.getValue().overrides.keySet()).containsExactly(123L); + // Package 3 + verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds( + any(CompatibilityOverrideConfig.class), eq(PACKAGE_3)); + verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds( + any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_3)); + } + + @Test + public void onPropertiesChanged_platformCompatThrowsExceptionForSomeCalls_skipsFailedCalls() + throws Exception { + mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 0); + mockGetApplicationInfo(PACKAGE_2, /* versionCode= */ 0); + mockGetApplicationInfo(PACKAGE_3, /* versionCode= */ 0); + mockGetApplicationInfo(PACKAGE_4, /* versionCode= */ 0); + doThrow(new RemoteException()).when(mPlatformCompat).putOverridesOnReleaseBuilds( + any(CompatibilityOverrideConfig.class), eq(PACKAGE_2)); + doThrow(new RemoteException()).when(mPlatformCompat).removeOverridesOnReleaseBuilds( + any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_3)); + + mService.registerDeviceConfigListeners(); + DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1) + .setString(PACKAGE_1, "123:::true,456:::") + .setString(PACKAGE_2, "123:::true,456:::") + .setString(PACKAGE_3, "123:::true,456:::") + .setString(PACKAGE_4, "123:::true,456:::").build()); + + // Package 1 + verify(mPlatformCompat).putOverridesOnReleaseBuilds(any(CompatibilityOverrideConfig.class), + eq(PACKAGE_1)); + verify(mPlatformCompat).removeOverridesOnReleaseBuilds( + any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_1)); + // Package 2 + verify(mPlatformCompat).putOverridesOnReleaseBuilds(any(CompatibilityOverrideConfig.class), + eq(PACKAGE_2)); + verify(mPlatformCompat).removeOverridesOnReleaseBuilds( + any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_2)); + // Package 3 + verify(mPlatformCompat).putOverridesOnReleaseBuilds(any(CompatibilityOverrideConfig.class), + eq(PACKAGE_3)); + verify(mPlatformCompat).removeOverridesOnReleaseBuilds( + any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_3)); + // Package 4 + verify(mPlatformCompat).putOverridesOnReleaseBuilds(any(CompatibilityOverrideConfig.class), + eq(PACKAGE_1)); + verify(mPlatformCompat).removeOverridesOnReleaseBuilds( + any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_4)); + } + + @Test + public void packageReceiver_packageAddedIntentDataIsNull_doesNothing() throws Exception { + DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1) + .setString(PACKAGE_1, "101:::true").build()); + DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_2) + .setString(PACKAGE_1, "201:::true").build()); + mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 0); + + mPackageReceiver.onReceive(mMockContext, new Intent(ACTION_PACKAGE_ADDED)); + + verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds( + any(CompatibilityOverrideConfig.class), eq(PACKAGE_1)); + verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds( + any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_1)); + } + + @Test + public void packageReceiver_actionIsNull_doesNothing() throws Exception { + DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1) + .setString(PACKAGE_1, "101:::true").build()); + DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_2) + .setString(PACKAGE_1, "201:::true").build()); + mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 0); + + mPackageReceiver.onReceive(mMockContext, + createPackageIntent(PACKAGE_1, /* action= */ null)); + + verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds( + any(CompatibilityOverrideConfig.class), eq(PACKAGE_1)); + verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds( + any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_1)); + } + + @Test + public void packageReceiver_unsupportedAction_doesNothing() throws Exception { + DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1) + .setString(PACKAGE_1, "101:::true").build()); + DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_2) + .setString(PACKAGE_1, "201:::true").build()); + mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 0); + + mPackageReceiver.onReceive(mMockContext, + createPackageIntent(PACKAGE_1, ACTION_USER_SWITCHED)); + + verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds( + any(CompatibilityOverrideConfig.class), eq(PACKAGE_1)); + verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds( + any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_1)); + } + + @Test + public void packageReceiver_packageAddedIntentPackageNotInstalled_doesNothing() + throws Exception { + DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1) + .setString(PACKAGE_1, "101:::true").build()); + DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_2) + .setString(PACKAGE_1, "201:::true").build()); + mockGetApplicationInfoNotInstalled(PACKAGE_1); + + mPackageReceiver.onReceive(mMockContext, + createPackageIntent(PACKAGE_1, ACTION_PACKAGE_ADDED)); + + verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds( + any(CompatibilityOverrideConfig.class), eq(PACKAGE_1)); + verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds( + any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_1)); + } + + @Test + public void packageReceiver_packageAddedIntentNoOverridesForPackage_doesNothing() + throws Exception { + DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1) + .setString(PACKAGE_2, "101:::true").build()); + DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_2) + .setString(PACKAGE_3, "201:::true").build()); + mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 0); + + mPackageReceiver.onReceive(mMockContext, + createPackageIntent(PACKAGE_1, ACTION_PACKAGE_ADDED)); + + verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds( + any(CompatibilityOverrideConfig.class), eq(PACKAGE_1)); + verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds( + any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_1)); + } + + @Test + public void packageReceiver_packageAddedIntent_appliesOverridesFromAllNamespaces() + throws Exception { + DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1) + .setString(PACKAGE_1, "101:::true,103:::") + .setString(PACKAGE_2, "102:::false").build()); + DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_2) + .setString(PACKAGE_3, "201:::false").build()); + DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_3) + .setString(PACKAGE_1, "301:::true,302:::false") + .setString(PACKAGE_2, "302:::false").build()); + mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 0); + + mPackageReceiver.onReceive(mMockContext, + createPackageIntent(PACKAGE_1, ACTION_PACKAGE_ADDED)); + + verify(mPlatformCompat, times(2)).putOverridesOnReleaseBuilds( + mOverridesToAddConfigCaptor.capture(), eq(PACKAGE_1)); + verify(mPlatformCompat).removeOverridesOnReleaseBuilds( + mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_1)); + List<CompatibilityOverrideConfig> configs = mOverridesToAddConfigCaptor.getAllValues(); + assertThat(configs.get(0).overrides.keySet()).containsExactly(101L); + assertThat(configs.get(1).overrides.keySet()).containsExactly(301L, 302L); + assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(103L); + } + + @Test + public void packageReceiver_packageChangedIntent_appliesOverrides() + throws Exception { + DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1) + .setString(PACKAGE_1, "101:::true,103:::").build()); + mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 0); + + mPackageReceiver.onReceive(mMockContext, + createPackageIntent(PACKAGE_1, ACTION_PACKAGE_CHANGED)); + + verify(mPlatformCompat).putOverridesOnReleaseBuilds( + mOverridesToAddConfigCaptor.capture(), eq(PACKAGE_1)); + verify(mPlatformCompat).removeOverridesOnReleaseBuilds( + mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_1)); + assertThat(mOverridesToAddConfigCaptor.getValue().overrides.keySet()).containsExactly(101L); + assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(103L); + } + + @Test + public void packageReceiver_packageAddedIntentRemoveOverridesSetForSomeNamespaces_skipsIds() + throws Exception { + DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1) + .setString(FLAG_REMOVE_OVERRIDES, PACKAGE_1 + "=103," + PACKAGE_2 + "=101") + .setString(PACKAGE_1, "101:::true,103:::") + .setString(PACKAGE_2, "102:::false").build()); + DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_2) + .setString(PACKAGE_1, "201:::false").build()); + DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_3) + .setString(FLAG_REMOVE_OVERRIDES, PACKAGE_1 + "=301," + PACKAGE_3 + "=302") + .setString(PACKAGE_1, "301:::true,302:::false,303:::") + .setString(PACKAGE_3, "302:::false").build()); + mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 0); + + mPackageReceiver.onReceive(mMockContext, + createPackageIntent(PACKAGE_1, ACTION_PACKAGE_ADDED)); + + verify(mPlatformCompat, times(3)).putOverridesOnReleaseBuilds( + mOverridesToAddConfigCaptor.capture(), eq(PACKAGE_1)); + verify(mPlatformCompat).removeOverridesOnReleaseBuilds( + mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_1)); + List<CompatibilityOverrideConfig> configs = mOverridesToAddConfigCaptor.getAllValues(); + assertThat(configs.get(0).overrides.keySet()).containsExactly(101L); + assertThat(configs.get(1).overrides.keySet()).containsExactly(201L); + assertThat(configs.get(2).overrides.keySet()).containsExactly(302L); + assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(303L); + } + + @Test + public void packageReceiver_packageRemovedIntentNoOverridesForPackage_doesNothing() + throws Exception { + DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1) + .setString(FLAG_OWNED_CHANGE_IDS, "101,102") + .setString(PACKAGE_2, "101:::true").build()); + DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_2) + .setString(FLAG_OWNED_CHANGE_IDS, "201,202") + .setString(PACKAGE_3, "201:::true").build()); + mockGetApplicationInfoNotInstalled(PACKAGE_1); + + mPackageReceiver.onReceive(mMockContext, + createPackageIntent(PACKAGE_1, ACTION_PACKAGE_REMOVED)); + + verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds( + any(CompatibilityOverrideConfig.class), eq(PACKAGE_1)); + verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds( + any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_1)); + } + + @Test + public void packageReceiver_packageRemovedIntentPackageInstalledForAnotherUser_doesNothing() + throws Exception { + DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1) + .setString(FLAG_OWNED_CHANGE_IDS, "101,102,103") + .setString(PACKAGE_1, "101:::true,103:::").build()); + DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_2) + .setString(FLAG_OWNED_CHANGE_IDS, "201,202") + .setString(PACKAGE_1, "202:::false").build()); + mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 0); + + mPackageReceiver.onReceive(mMockContext, + createPackageIntent(PACKAGE_1, ACTION_PACKAGE_REMOVED)); + + verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds( + any(CompatibilityOverrideConfig.class), eq(PACKAGE_1)); + verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds( + any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_1)); + } + + @Test + public void packageReceiver_packageRemovedIntent_removesOwnedOverridesForNamespacesWithPackage() + throws Exception { + DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1) + .setString(FLAG_OWNED_CHANGE_IDS, "101,102,103") + .setString(PACKAGE_1, "101:::true,103:::") + .setString(PACKAGE_2, "102:::false").build()); + DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_2) + .setString(FLAG_OWNED_CHANGE_IDS, "201") + .setString(PACKAGE_3, "201:::false").build()); + DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_3) + .setString(FLAG_OWNED_CHANGE_IDS, "301,302") + .setString(PACKAGE_1, "302:::") + .setString(PACKAGE_2, "301:::true").build()); + mockGetApplicationInfoNotInstalled(PACKAGE_1); + + mPackageReceiver.onReceive(mMockContext, + createPackageIntent(PACKAGE_1, ACTION_PACKAGE_REMOVED)); + + verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds( + any(CompatibilityOverrideConfig.class), eq(PACKAGE_1)); + verify(mPlatformCompat, times(2)).removeOverridesOnReleaseBuilds( + mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_1)); + List<CompatibilityOverridesToRemoveConfig> configs = + mOverridesToRemoveConfigCaptor.getAllValues(); + assertThat(configs.get(0).changeIds).containsExactly(101L, 102L, 103L); + assertThat(configs.get(1).changeIds).containsExactly(301L, 302L); + } + + @Test + public void packageReceiver_packageRemovedIntentNoOwnedIdsForSomeNamespace_skipsNamespace() + throws Exception { + DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1) + .setString(FLAG_OWNED_CHANGE_IDS, "101,102") + .setString(PACKAGE_1, "101:::true").build()); + DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_2) + .setString(PACKAGE_1, "201:::false").build()); + DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_3) + .setString(FLAG_OWNED_CHANGE_IDS, "301") + .setString(PACKAGE_1, "301:::true").build()); + mockGetApplicationInfoNotInstalled(PACKAGE_1); + + mPackageReceiver.onReceive(mMockContext, + createPackageIntent(PACKAGE_1, ACTION_PACKAGE_REMOVED)); + + verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds( + any(CompatibilityOverrideConfig.class), eq(PACKAGE_1)); + verify(mPlatformCompat, times(2)).removeOverridesOnReleaseBuilds( + mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_1)); + List<CompatibilityOverridesToRemoveConfig> configs = + mOverridesToRemoveConfigCaptor.getAllValues(); + assertThat(configs.get(0).changeIds).containsExactly(101L, 102L); + assertThat(configs.get(1).changeIds).containsExactly(301L); + } + + @Test + public void packageReceiver_platformCompatThrowsExceptionForSomeNamespace_skipsFailedCall() + throws Exception { + DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1) + .setString(PACKAGE_1, "101:::true").build()); + DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_2) + .setString(PACKAGE_1, "201:::false").build()); + DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_3) + .setString(PACKAGE_1, "301:::true").build()); + mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 0); + doThrow(new RemoteException()).when(mPlatformCompat).putOverridesOnReleaseBuilds( + argThat(config -> config.overrides.containsKey(201L)), eq(PACKAGE_1)); + + mPackageReceiver.onReceive(mMockContext, + createPackageIntent(PACKAGE_1, ACTION_PACKAGE_ADDED)); + + verify(mPlatformCompat, times(3)).putOverridesOnReleaseBuilds( + any(CompatibilityOverrideConfig.class), eq(PACKAGE_1)); + verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds( + any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_1)); + } + + private void mockGetApplicationInfo(String packageName, long versionCode) + throws Exception { + when(mPackageManager.getApplicationInfo(eq(packageName), anyInt())).thenReturn( + createAppInfo(versionCode)); + } + + private void mockGetApplicationInfoNotInstalled(String packageName) throws Exception { + when(mPackageManager.getApplicationInfo(eq(packageName), anyInt())) + .thenThrow(new PackageManager.NameNotFoundException()); + } + + private static ApplicationInfo createAppInfo(long versionCode) { + ApplicationInfo appInfo = new ApplicationInfo(); + appInfo.longVersionCode = versionCode; + return appInfo; + } + + private Intent createPackageIntent(String packageName, @Nullable String action) { + return new Intent(action, Uri.parse("package:" + packageName)); + } +} diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/FrameworkOptimizeStrategyTest.java b/services/tests/servicestests/src/com/android/server/appsearch/FrameworkOptimizeStrategyTest.java index de71d21e6eb1..8389c85477ea 100644 --- a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/FrameworkOptimizeStrategyTest.java +++ b/services/tests/servicestests/src/com/android/server/appsearch/FrameworkOptimizeStrategyTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 The Android Open Source Project + * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,12 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +package com.android.server.appsearch; -package com.android.server.appsearch.external.localstorage; - -import static com.android.server.appsearch.external.localstorage.FrameworkOptimizeStrategy.BYTES_OPTIMIZE_THRESHOLD; -import static com.android.server.appsearch.external.localstorage.FrameworkOptimizeStrategy.DOC_COUNT_OPTIMIZE_THRESHOLD; -import static com.android.server.appsearch.external.localstorage.FrameworkOptimizeStrategy.TIME_OPTIMIZE_THRESHOLD_MILLIS; +import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR; import static com.google.common.truth.Truth.assertThat; @@ -28,14 +25,17 @@ import com.android.server.appsearch.icing.proto.StatusProto; import org.junit.Test; public class FrameworkOptimizeStrategyTest { - FrameworkOptimizeStrategy mFrameworkOptimizeStrategy = new FrameworkOptimizeStrategy(); + AppSearchConfig mAppSearchConfig = AppSearchConfig.create(DIRECT_EXECUTOR); + FrameworkOptimizeStrategy mFrameworkOptimizeStrategy = + new FrameworkOptimizeStrategy(mAppSearchConfig); @Test - public void testShouldOptimize_docCountThreshold() { + public void testShouldOptimize_byteThreshold() { GetOptimizeInfoResultProto optimizeInfo = GetOptimizeInfoResultProto.newBuilder() .setTimeSinceLastOptimizeMs(0) - .setEstimatedOptimizableBytes(BYTES_OPTIMIZE_THRESHOLD) + .setEstimatedOptimizableBytes( + mAppSearchConfig.getCachedBytesOptimizeThreshold()) .setOptimizableDocs(0) .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.OK).build()) .build(); @@ -43,10 +43,11 @@ public class FrameworkOptimizeStrategyTest { } @Test - public void testShouldOptimize_byteThreshold() { + public void testShouldNotOptimize_timeThreshold() { GetOptimizeInfoResultProto optimizeInfo = GetOptimizeInfoResultProto.newBuilder() - .setTimeSinceLastOptimizeMs(TIME_OPTIMIZE_THRESHOLD_MILLIS) + .setTimeSinceLastOptimizeMs( + mAppSearchConfig.getCachedTimeOptimizeThresholdMs()) .setEstimatedOptimizableBytes(0) .setOptimizableDocs(0) .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.OK).build()) @@ -55,12 +56,13 @@ public class FrameworkOptimizeStrategyTest { } @Test - public void testShouldNotOptimize_timeThreshold() { + public void testShouldOptimize_docCountThreshold() { GetOptimizeInfoResultProto optimizeInfo = GetOptimizeInfoResultProto.newBuilder() .setTimeSinceLastOptimizeMs(0) .setEstimatedOptimizableBytes(0) - .setOptimizableDocs(DOC_COUNT_OPTIMIZE_THRESHOLD) + .setOptimizableDocs( + mAppSearchConfig.getCachedDocCountOptimizeThreshold()) .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.OK).build()) .build(); assertThat(mFrameworkOptimizeStrategy.shouldOptimize(optimizeInfo)).isTrue(); diff --git a/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java b/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java index fbcf53d3bd4a..7243947db944 100644 --- a/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java @@ -74,6 +74,9 @@ public class HighBrightnessModeControllerTest { private static final float DEFAULT_MIN = 0.01f; private static final float DEFAULT_MAX = 0.80f; + private static final int DISPLAY_WIDTH = 900; + private static final int DISPLAY_HEIGHT = 1600; + private static final float EPSILON = 0.000001f; private OffsettableClock mClock; @@ -90,6 +93,8 @@ public class HighBrightnessModeControllerTest { @Captor ArgumentCaptor<IThermalEventListener> mThermalEventListenerCaptor; + @Mock private BrightnessSetting mBrightnessSetting; + private static final HighBrightnessModeData DEFAULT_HBM_DATA = new HighBrightnessModeData(MINIMUM_LUX, TRANSITION_POINT, TIME_WINDOW_MILLIS, TIME_ALLOWED_IN_WINDOW_MILLIS, TIME_MINIMUM_AVAILABLE_TO_ENABLE_MILLIS, @@ -98,6 +103,8 @@ public class HighBrightnessModeControllerTest { @Before public void setUp() { MockitoAnnotations.initMocks(this); + mClock = new OffsettableClock.Stopped(); + mTestLooper = new TestLooper(mClock::now); mDisplayToken = null; mContextSpy = spy(new ContextWrapper(ApplicationProvider.getApplicationContext())); final MockContentResolver resolver = mSettingsProviderRule.mockContentResolver(mContextSpy); @@ -114,8 +121,8 @@ public class HighBrightnessModeControllerTest { public void testNoHbmData() { initHandler(null); final HighBrightnessModeController hbmc = new HighBrightnessModeController( - mInjectorMock, mHandler, mDisplayToken, DEFAULT_MIN, DEFAULT_MAX, null, - () -> {}, mContextSpy); + mInjectorMock, mHandler, DISPLAY_WIDTH, DISPLAY_HEIGHT, mDisplayToken, DEFAULT_MIN, + DEFAULT_MAX, null, () -> {}, mContextSpy, mBrightnessSetting); assertState(hbmc, DEFAULT_MIN, DEFAULT_MAX, HIGH_BRIGHTNESS_MODE_OFF); } @@ -123,8 +130,8 @@ public class HighBrightnessModeControllerTest { public void testNoHbmData_Enabled() { initHandler(null); final HighBrightnessModeController hbmc = new HighBrightnessModeController( - mInjectorMock, mHandler, mDisplayToken, DEFAULT_MIN, DEFAULT_MAX, null, - () -> {}, mContextSpy); + mInjectorMock, mHandler, DISPLAY_WIDTH, DISPLAY_HEIGHT, mDisplayToken, DEFAULT_MIN, + DEFAULT_MAX, null, () -> {}, mContextSpy, mBrightnessSetting); hbmc.setAutoBrightnessEnabled(true); hbmc.onAmbientLuxChange(MINIMUM_LUX - 1); // below allowed range assertState(hbmc, DEFAULT_MIN, DEFAULT_MAX, HIGH_BRIGHTNESS_MODE_OFF); @@ -180,7 +187,7 @@ public class HighBrightnessModeControllerTest { hbmc.setAutoBrightnessEnabled(true); hbmc.onAmbientLuxChange(MINIMUM_LUX + 1); - hbmc.onAutoBrightnessChanged(TRANSITION_POINT + 0.01f); + hbmc.onBrightnessChanged(TRANSITION_POINT + 0.01f); // Verify we are in HBM assertState(hbmc, DEFAULT_MIN, DEFAULT_MAX, HIGH_BRIGHTNESS_MODE_SUNLIGHT); @@ -212,7 +219,7 @@ public class HighBrightnessModeControllerTest { hbmc.setAutoBrightnessEnabled(true); hbmc.onAmbientLuxChange(MINIMUM_LUX + 1); - hbmc.onAutoBrightnessChanged(TRANSITION_POINT + 0.01f); + hbmc.onBrightnessChanged(TRANSITION_POINT + 0.01f); // Verify we are in HBM assertState(hbmc, DEFAULT_MIN, DEFAULT_MAX, HIGH_BRIGHTNESS_MODE_SUNLIGHT); @@ -237,18 +244,18 @@ public class HighBrightnessModeControllerTest { hbmc.setAutoBrightnessEnabled(true); hbmc.onAmbientLuxChange(MINIMUM_LUX + 1); - hbmc.onAutoBrightnessChanged(TRANSITION_POINT + 0.01f); + hbmc.onBrightnessChanged(TRANSITION_POINT + 0.01f); advanceTime(TIME_ALLOWED_IN_WINDOW_MILLIS / 2); // Verify we are in HBM assertState(hbmc, DEFAULT_MIN, DEFAULT_MAX, HIGH_BRIGHTNESS_MODE_SUNLIGHT); - hbmc.onAutoBrightnessChanged(TRANSITION_POINT - 0.01f); + hbmc.onBrightnessChanged(TRANSITION_POINT - 0.01f); advanceTime(1); assertState(hbmc, DEFAULT_MIN, DEFAULT_MAX, HIGH_BRIGHTNESS_MODE_SUNLIGHT); - hbmc.onAutoBrightnessChanged(TRANSITION_POINT + 0.01f); + hbmc.onBrightnessChanged(TRANSITION_POINT + 0.01f); advanceTime(TIME_ALLOWED_IN_WINDOW_MILLIS / 2); assertState(hbmc, DEFAULT_MIN, DEFAULT_MAX, HIGH_BRIGHTNESS_MODE_SUNLIGHT); @@ -267,13 +274,13 @@ public class HighBrightnessModeControllerTest { hbmc.onAmbientLuxChange(MINIMUM_LUX + 1); // Go into HBM for half the allowed window - hbmc.onAutoBrightnessChanged(TRANSITION_POINT + 0.01f); + hbmc.onBrightnessChanged(TRANSITION_POINT + 0.01f); advanceTime(TIME_ALLOWED_IN_WINDOW_MILLIS / 2); assertState(hbmc, DEFAULT_MIN, DEFAULT_MAX, HIGH_BRIGHTNESS_MODE_SUNLIGHT); // Move lux below threshold (ending first event); hbmc.onAmbientLuxChange(MINIMUM_LUX - 1); - hbmc.onAutoBrightnessChanged(TRANSITION_POINT); + hbmc.onBrightnessChanged(TRANSITION_POINT); assertState(hbmc, DEFAULT_MIN, TRANSITION_POINT, HIGH_BRIGHTNESS_MODE_OFF); // Move up some amount of time so that there's still time in the window even after a @@ -283,7 +290,7 @@ public class HighBrightnessModeControllerTest { // Go into HBM for just under the second half of allowed window hbmc.onAmbientLuxChange(MINIMUM_LUX + 1); - hbmc.onAutoBrightnessChanged(TRANSITION_POINT + 1); + hbmc.onBrightnessChanged(TRANSITION_POINT + 1); advanceTime((TIME_ALLOWED_IN_WINDOW_MILLIS / 2) - 1); assertState(hbmc, DEFAULT_MIN, DEFAULT_MAX, HIGH_BRIGHTNESS_MODE_SUNLIGHT); @@ -355,8 +362,9 @@ public class HighBrightnessModeControllerTest { // Creates instance with standard initialization values. private HighBrightnessModeController createDefaultHbm(OffsettableClock clock) { initHandler(clock); - return new HighBrightnessModeController(mInjectorMock, mHandler, mDisplayToken, DEFAULT_MIN, - DEFAULT_MAX, DEFAULT_HBM_DATA, () -> {}, mContextSpy); + return new HighBrightnessModeController(mInjectorMock, mHandler, DISPLAY_WIDTH, + DISPLAY_HEIGHT, mDisplayToken, DEFAULT_MIN, DEFAULT_MAX, DEFAULT_HBM_DATA, () -> {}, + mContextSpy, mBrightnessSetting); } private void initHandler(OffsettableClock clock) { diff --git a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java index fb768a815624..8b8a7e631caf 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java @@ -37,6 +37,7 @@ import android.apex.ApexSessionInfo; import android.apex.ApexSessionParams; import android.apex.IApexService; import android.content.Context; +import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.os.RemoteException; import android.platform.test.annotations.Presubmit; @@ -349,9 +350,9 @@ public class ApexManagerTest { } @Test - public void testInstallPackage() throws Exception { + public void testInstallPackage_activeOnSystem() throws Exception { ApexInfo activeApexInfo = createApexInfo("test.apex_rebootless", 1, /* isActive= */ true, - /* isFactory= */ false, extractResource("test.apex_rebootless_v1", + /* isFactory= */ true, extractResource("test.apex_rebootless_v1", "test.rebootless_apex_v1.apex")); when(mApexService.getAllPackages()).thenReturn(new ApexInfo[]{activeApexInfo}); mApexManager.scanApexPackagesTraced(mPackageParser2, @@ -369,6 +370,55 @@ public class ApexManagerTest { ApexManager.MATCH_ACTIVE_PACKAGE); assertThat(newInfo.applicationInfo.sourceDir).isEqualTo(finalApex.getAbsolutePath()); assertThat(newInfo.applicationInfo.longVersionCode).isEqualTo(2); + assertThat(newInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM).isEqualTo(0); + assertThat(newInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) + .isEqualTo(ApplicationInfo.FLAG_INSTALLED); + + PackageInfo factoryInfo = mApexManager.getPackageInfo("test.apex.rebootless", + ApexManager.MATCH_FACTORY_PACKAGE); + assertThat(factoryInfo.applicationInfo.sourceDir).isEqualTo(activeApexInfo.modulePath); + assertThat(factoryInfo.applicationInfo.longVersionCode).isEqualTo(1); + assertThat(factoryInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) + .isEqualTo(ApplicationInfo.FLAG_SYSTEM); + assertThat(factoryInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED).isEqualTo(0); + } + + @Test + public void testInstallPackage_activeOnData() throws Exception { + ApexInfo factoryApexInfo = createApexInfo("test.apex_rebootless", 1, /* isActive= */ false, + /* isFactory= */ true, extractResource("test.apex_rebootless_v1", + "test.rebootless_apex_v1.apex")); + ApexInfo activeApexInfo = createApexInfo("test.apex_rebootless", 1, /* isActive= */ true, + /* isFactory= */ false, extractResource("test.apex.rebootless@1", + "test.rebootless_apex_v1.apex")); + when(mApexService.getAllPackages()) + .thenReturn(new ApexInfo[]{factoryApexInfo, activeApexInfo}); + mApexManager.scanApexPackagesTraced(mPackageParser2, + ParallelPackageParser.makeExecutorService()); + + File finalApex = extractResource("test.rebootles_apex_v2", "test.rebootless_apex_v2.apex"); + ApexInfo newApexInfo = createApexInfo("test.apex_rebootless", 2, /* isActive= */ true, + /* isFactory= */ false, finalApex); + when(mApexService.installAndActivatePackage(anyString())).thenReturn(newApexInfo); + + File installedApex = extractResource("installed", "test.rebootless_apex_v2.apex"); + mApexManager.installPackage(installedApex, mPackageParser2); + + PackageInfo newInfo = mApexManager.getPackageInfo("test.apex.rebootless", + ApexManager.MATCH_ACTIVE_PACKAGE); + assertThat(newInfo.applicationInfo.sourceDir).isEqualTo(finalApex.getAbsolutePath()); + assertThat(newInfo.applicationInfo.longVersionCode).isEqualTo(2); + assertThat(newInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM).isEqualTo(0); + assertThat(newInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) + .isEqualTo(ApplicationInfo.FLAG_INSTALLED); + + PackageInfo factoryInfo = mApexManager.getPackageInfo("test.apex.rebootless", + ApexManager.MATCH_FACTORY_PACKAGE); + assertThat(factoryInfo.applicationInfo.sourceDir).isEqualTo(factoryApexInfo.modulePath); + assertThat(factoryInfo.applicationInfo.longVersionCode).isEqualTo(1); + assertThat(factoryInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) + .isEqualTo(ApplicationInfo.FLAG_SYSTEM); + assertThat(factoryInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED).isEqualTo(0); } @Test diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java index 29f4aa976ef6..22fb76b1fbe5 100644 --- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java +++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java @@ -198,6 +198,7 @@ public class PackageManagerSettingsTests { new WatchableTester(settingsUnderTest, "noSuspendingPackage"); watcher.register(); settingsUnderTest.mPackages.put(PACKAGE_NAME_1, createPackageSetting(PACKAGE_NAME_1)); + settingsUnderTest.readPackageRestrictionsLPr(0); watcher.verifyChangeReported("put package 1"); // Collect a snapshot at the midway point (package 2 has not been added) final Settings snapshot = settingsUnderTest.snapshot(); 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 614949c91b9a..69f006568c8e 100644 --- a/services/tests/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java @@ -292,23 +292,29 @@ public class UriGrantsManagerServiceTest { intent.setClipData(clip); { - // When granting towards primary, persistable can't be honored so - // the entire grant fails - try { - mService.checkGrantUriPermissionFromIntent( - intent, UID_PRIMARY_CAMERA, PKG_SOCIAL, USER_PRIMARY); - fail(); - } catch (SecurityException expected) { + // The camera package shouldn't be able to see other packages or their providers, + // so make sure the grant only succeeds for the camera's URIs. + final NeededUriGrants nug = mService.checkGrantUriPermissionFromIntent( + intent, UID_PRIMARY_CAMERA, PKG_SOCIAL, USER_PRIMARY); + if (nug != null && nug.uris != null) { + for (GrantUri gu : nug.uris) { + if (!gu.uri.getAuthority().equals(PKG_CAMERA)) { + fail(); + } + } } } { - // When granting towards secondary, persistable can't be honored so - // the entire grant fails - try { - mService.checkGrantUriPermissionFromIntent( - intent, UID_PRIMARY_CAMERA, PKG_SOCIAL, USER_SECONDARY); - fail(); - } catch (SecurityException expected) { + // The camera package shouldn't be able to see other packages or their providers, + // so make sure the grant only succeeds for the camera's URIs. + final NeededUriGrants nug = mService.checkGrantUriPermissionFromIntent( + intent, UID_PRIMARY_CAMERA, PKG_SOCIAL, USER_SECONDARY); + if (nug != null && nug.uris != null) { + for (GrantUri gu : nug.uris) { + if (!gu.uri.getAuthority().equals(PKG_CAMERA)) { + fail(); + } + } } } } diff --git a/services/tests/servicestests/src/com/android/server/uri/UriGrantsMockContext.java b/services/tests/servicestests/src/com/android/server/uri/UriGrantsMockContext.java index 2c719ff9e8b3..a6307b38f6a5 100644 --- a/services/tests/servicestests/src/com/android/server/uri/UriGrantsMockContext.java +++ b/services/tests/servicestests/src/com/android/server/uri/UriGrantsMockContext.java @@ -135,14 +135,29 @@ public class UriGrantsMockContext extends ContextWrapper { when(mPmInternal.resolveContentProvider(eq(PKG_CAMERA), anyInt(), eq(userId))) .thenReturn(buildCameraProvider(userId)); + when(mPmInternal.resolveContentProvider(eq(PKG_CAMERA), anyInt(), eq(userId), + eq(UserHandle.getUid(userId, UID_CAMERA)))) + .thenReturn(buildCameraProvider(userId)); when(mPmInternal.resolveContentProvider(eq(PKG_PRIVATE), anyInt(), eq(userId))) .thenReturn(buildPrivateProvider(userId)); + when(mPmInternal.resolveContentProvider(eq(PKG_PRIVATE), anyInt(), eq(userId), + eq(UserHandle.getUid(userId, UID_PRIVATE)))) + .thenReturn(buildPrivateProvider(userId)); when(mPmInternal.resolveContentProvider(eq(PKG_PUBLIC), anyInt(), eq(userId))) .thenReturn(buildPublicProvider(userId)); + when(mPmInternal.resolveContentProvider(eq(PKG_PUBLIC), anyInt(), eq(userId), + eq(UserHandle.getUid(userId, UID_PUBLIC)))) + .thenReturn(buildPublicProvider(userId)); when(mPmInternal.resolveContentProvider(eq(PKG_FORCE), anyInt(), eq(userId))) .thenReturn(buildForceProvider(userId)); + when(mPmInternal.resolveContentProvider(eq(PKG_FORCE), anyInt(), eq(userId), + eq(UserHandle.getUid(userId, UID_FORCE)))) + .thenReturn(buildForceProvider(userId)); when(mPmInternal.resolveContentProvider(eq(PKG_COMPLEX), anyInt(), eq(userId))) .thenReturn(buildComplexProvider(userId)); + when(mPmInternal.resolveContentProvider(eq(PKG_COMPLEX), anyInt(), eq(userId), + eq(UserHandle.getUid(userId, UID_COMPLEX)))) + .thenReturn(buildComplexProvider(userId)); } } diff --git a/services/tests/servicestests/src/com/android/server/vibrator/FakeVibratorControllerProvider.java b/services/tests/servicestests/src/com/android/server/vibrator/FakeVibratorControllerProvider.java index 0449e4450d06..75f8a44c6f86 100644 --- a/services/tests/servicestests/src/com/android/server/vibrator/FakeVibratorControllerProvider.java +++ b/services/tests/servicestests/src/com/android/server/vibrator/FakeVibratorControllerProvider.java @@ -46,6 +46,7 @@ final class FakeVibratorControllerProvider { private final List<VibrationEffectSegment> mEffectSegments = new ArrayList<>(); private final List<Integer> mBraking = new ArrayList<>(); private final List<Float> mAmplitudes = new ArrayList<>(); + private final List<Boolean> mExternalControlStates = new ArrayList<>(); private final Handler mHandler; private final FakeNativeWrapper mNativeWrapper; @@ -139,6 +140,7 @@ final class FakeVibratorControllerProvider { @Override public void setExternalControl(boolean enabled) { + mExternalControlStates.add(enabled); } @Override @@ -301,6 +303,11 @@ final class FakeVibratorControllerProvider { return new ArrayList<>(mEffectSegments); } + /** Return list of states set for external control to the fake vibrator hardware. */ + public List<Boolean> getExternalControlStates() { + return mExternalControlStates; + } + /** * Return the {@link PrebakedSegment} effect enabled with given id, or {@code null} if * missing or disabled. diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java index 77003b2e091a..5a00e0d6530d 100644 --- a/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java @@ -35,6 +35,7 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import android.app.AppOpsManager; @@ -50,8 +51,11 @@ import android.hardware.vibrator.IVibratorManager; import android.media.AudioAttributes; import android.media.AudioManager; import android.os.CombinedVibration; +import android.os.ExternalVibration; import android.os.Handler; import android.os.IBinder; +import android.os.IExternalVibrationController; +import android.os.IExternalVibratorService; import android.os.IVibratorStateListener; import android.os.Looper; import android.os.PowerManager; @@ -108,6 +112,8 @@ public class VibratorManagerServiceTest { private static final PowerSaveState NORMAL_POWER_STATE = new PowerSaveState.Builder().build(); private static final PowerSaveState LOW_POWER_STATE = new PowerSaveState.Builder() .setBatterySaverEnabled(true).build(); + private static final AudioAttributes AUDIO_ATTRS = + new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ALARM).build(); private static final VibrationAttributes ALARM_ATTRS = new VibrationAttributes.Builder().setUsage(VibrationAttributes.USAGE_ALARM).build(); private static final VibrationAttributes HAPTIC_FEEDBACK_ATTRS = @@ -136,6 +142,7 @@ public class VibratorManagerServiceTest { private TestLooper mTestLooper; private FakeVibrator mVibrator; private PowerManagerInternal.LowPowerModeListener mRegisteredPowerModeListener; + private VibratorManagerService.ExternalVibratorService mExternalVibratorService; @Before public void setUp() throws Exception { @@ -208,6 +215,9 @@ public class VibratorManagerServiceTest { @Override void addService(String name, IBinder service) { + Object serviceInstance = service; + mExternalVibratorService = + (VibratorManagerService.ExternalVibratorService) serviceInstance; } }); } @@ -967,6 +977,69 @@ public class VibratorManagerServiceTest { assertTrue(waitUntil(s -> !s.isVibrating(1), service, TEST_TIMEOUT_MILLIS)); } + @Test + public void onExternalVibration_setsExternalControl() { + mockVibrators(1); + mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_EXTERNAL_CONTROL); + createSystemReadyService(); + + ExternalVibration externalVibration = new ExternalVibration(UID, PACKAGE_NAME, AUDIO_ATTRS, + mock(IExternalVibrationController.class)); + int scale = mExternalVibratorService.onExternalVibrationStart(externalVibration); + mExternalVibratorService.onExternalVibrationStop(externalVibration); + + assertEquals(IExternalVibratorService.SCALE_NONE, scale); + assertEquals(Arrays.asList(true, false), + mVibratorProviders.get(1).getExternalControlStates()); + } + + @Test + public void onExternalVibration_withOngoingExternalVibration_mutesPreviousVibration() + throws Exception { + mockVibrators(1); + mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_EXTERNAL_CONTROL); + createSystemReadyService(); + + IExternalVibrationController firstController = mock(IExternalVibrationController.class); + IExternalVibrationController secondController = mock(IExternalVibrationController.class); + ExternalVibration firstVibration = new ExternalVibration(UID, PACKAGE_NAME, AUDIO_ATTRS, + firstController); + int firstScale = mExternalVibratorService.onExternalVibrationStart(firstVibration); + + ExternalVibration secondVibration = new ExternalVibration(UID, PACKAGE_NAME, AUDIO_ATTRS, + secondController); + int secondScale = mExternalVibratorService.onExternalVibrationStart(secondVibration); + + assertEquals(IExternalVibratorService.SCALE_NONE, firstScale); + assertEquals(IExternalVibratorService.SCALE_NONE, secondScale); + verify(firstController).mute(); + verifyNoMoreInteractions(secondController); + // Set external control called only once. + assertEquals(Arrays.asList(true), mVibratorProviders.get(1).getExternalControlStates()); + } + + @Test + public void onExternalVibration_withOngoingVibration_cancelsOngoingVibrationImmediately() + throws Exception { + mockVibrators(1); + mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_EXTERNAL_CONTROL, + IVibrator.CAP_AMPLITUDE_CONTROL); + VibratorManagerService service = createSystemReadyService(); + + VibrationEffect effect = VibrationEffect.createOneShot(10 * TEST_TIMEOUT_MILLIS, 100); + vibrate(service, effect, HAPTIC_FEEDBACK_ATTRS); + assertTrue(waitUntil(s -> s.isVibrating(1), service, TEST_TIMEOUT_MILLIS)); + + ExternalVibration externalVibration = new ExternalVibration(UID, PACKAGE_NAME, AUDIO_ATTRS, + mock(IExternalVibrationController.class)); + int scale = mExternalVibratorService.onExternalVibrationStart(externalVibration); + assertEquals(IExternalVibratorService.SCALE_NONE, scale); + + // Vibration is cancelled. + assertTrue(waitUntil(s -> !s.isVibrating(1), service, TEST_TIMEOUT_MILLIS)); + assertEquals(Arrays.asList(true), mVibratorProviders.get(1).getExternalControlStates()); + } + private VibrationEffectSegment expectedPrebaked(int effectId) { return new PrebakedSegment(effectId, false, VibrationEffect.EFFECT_STRENGTH_MEDIUM); } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java index 825e53e15ea8..f9663f200b56 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java @@ -279,6 +279,36 @@ public class ManagedServicesTest extends UiServiceTestCase { } @Test + public void testReadXml_noLongerMigrateFromSettings() throws Exception { + for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) { + ManagedServices service = new TestManagedServicesNoSettings(getContext(), mLock, + mUserProfiles, mIpm, approvalLevel); + + // approved services aren't in xml + TypedXmlPullParser parser = Xml.newFastPullParser(); + parser.setInput(new BufferedInputStream(new ByteArrayInputStream(new byte[]{})), + null); + writeExpectedValuesToSettings(approvalLevel); + + service.migrateToXml(); + // No crash? success + + ArrayMap<Integer, String> verifyMap = approvalLevel == APPROVAL_BY_COMPONENT + ? mExpectedPrimary.get(service.mApprovalLevel) + : mExpectedSecondary.get(service.mApprovalLevel); + for (int userId : verifyMap.keySet()) { + for (String verifyValue : verifyMap.get(userId).split(":")) { + if (!TextUtils.isEmpty(verifyValue)) { + assertFalse("service type " + service.mApprovalLevel + ":" + + verifyValue + " is allowed for user " + userId, + service.isPackageOrComponentAllowed(verifyValue, userId)); + } + } + } + } + } + + @Test public void testReadXml() throws Exception { for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) { ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles, @@ -1766,4 +1796,25 @@ public class ManagedServicesTest extends UiServiceTestCase { return true; } } + + class TestManagedServicesNoSettings extends TestManagedServices { + + public TestManagedServicesNoSettings(Context context, Object mutex, UserProfiles userProfiles, + IPackageManager pm, int approvedServiceType) { + super(context, mutex, userProfiles, pm, approvedServiceType); + } + + @Override + protected Config getConfig() { + Config c = super.getConfig(); + c.secureSettingName = null; + c.secondarySettingName = null; + return c; + } + + @Override + public boolean shouldReflectToSettings() { + return false; + } + } } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java index d0bf63a1680f..733d3f0f66ef 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java @@ -281,6 +281,34 @@ public class ZenModeConfigTest extends UiServiceTestCase { assertNull(fromXml.pkg); } + @Test + public void testRuleXml_getPkg_nullPkg() throws Exception { + String tag = "tag"; + + ZenModeConfig.ZenRule rule = new ZenModeConfig.ZenRule(); + rule.enabled = true; + rule.configurationActivity = new ComponentName("a", "a"); + + TypedXmlSerializer out = Xml.newFastSerializer(); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + out.setOutput(new BufferedOutputStream(baos), "utf-8"); + out.startDocument(null, true); + out.startTag(null, tag); + ZenModeConfig.writeRuleXml(rule, out); + out.endTag(null, tag); + out.endDocument(); + + TypedXmlPullParser parser = Xml.newFastPullParser(); + parser.setInput(new BufferedInputStream( + new ByteArrayInputStream(baos.toByteArray())), null); + parser.nextTag(); + ZenModeConfig.ZenRule fromXml = ZenModeConfig.readRuleXml(parser); + assertEquals("a", fromXml.getPkg()); + + fromXml.condition = new Condition(Uri.EMPTY, "", Condition.STATE_TRUE); + assertTrue(fromXml.isAutomaticActive()); + } + private ZenModeConfig getMutedRingerConfig() { ZenModeConfig config = new ZenModeConfig(); // Allow alarms, media diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java index 00dbaf649ca2..4410404b0cd7 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java @@ -33,6 +33,7 @@ import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCRE import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK; import static android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; +import static android.service.notification.Condition.STATE_TRUE; import static android.util.StatsLog.ANNOTATION_ID_IS_UID; import static com.android.internal.util.FrameworkStatsLog.DND_MODE_RULE; @@ -49,6 +50,7 @@ import static junit.framework.TestCase.assertTrue; import static junit.framework.TestCase.fail; import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNull; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; @@ -64,6 +66,8 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.AppGlobals; import android.app.AppOpsManager; import android.app.AutomaticZenRule; @@ -72,7 +76,9 @@ import android.app.NotificationManager.Policy; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; +import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; import android.content.res.Resources; import android.content.res.XmlResourceParser; import android.media.AudioAttributes; @@ -81,6 +87,7 @@ import android.media.AudioManagerInternal; import android.media.AudioSystem; import android.media.VolumePolicy; import android.net.Uri; +import android.os.Binder; import android.os.Process; import android.os.UserHandle; import android.provider.Settings; @@ -105,6 +112,8 @@ import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; import com.android.server.UiServiceTestCase; import com.android.server.notification.ManagedServices.UserProfiles; +import com.google.common.collect.ImmutableList; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -172,8 +181,14 @@ public class ZenModeHelperTest extends UiServiceTestCase { mZenModeHelperSpy = spy(new ZenModeHelper(mContext, mTestableLooper.getLooper(), mConditionProviders, mStatsEventBuilderFactory)); + ResolveInfo ri = new ResolveInfo(); + ri.activityInfo = new ActivityInfo(); + when(mPackageManager.queryIntentActivitiesAsUser(any(), anyInt(), anyInt())).thenReturn( + ImmutableList.of(ri)); when(mPackageManager.getPackageUidAsUser(eq(CUSTOM_PKG_NAME), anyInt())) .thenReturn(CUSTOM_PKG_UID); + when(mPackageManager.getPackagesForUid(anyInt())).thenReturn( + new String[] {getContext().getPackageName()}); mZenModeHelperSpy.mPm = mPackageManager; } @@ -1486,7 +1501,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { mZenModeHelperSpy.mConfig.manualRule.component = new ComponentName("android", CountdownConditionProvider.class.getName()); mZenModeHelperSpy.mConfig.manualRule.condition = new Condition(conditionId, "", "", "", 0, - Condition.STATE_TRUE, Condition.FLAG_RELEVANT_NOW); + STATE_TRUE, Condition.FLAG_RELEVANT_NOW); mZenModeHelperSpy.mConfig.manualRule.enabled = true; ZenModeConfig originalConfig = mZenModeHelperSpy.mConfig.copy(); @@ -1592,10 +1607,12 @@ public class ZenModeHelperTest extends UiServiceTestCase { } @Test - public void testAddAutomaticZenRule() { + public void testAddAutomaticZenRule_CA() { AutomaticZenRule zenRule = new AutomaticZenRule("name", + null, new ComponentName("android", "ScheduleConditionProvider"), ZenModeConfig.toScheduleConditionId(new ScheduleInfo()), + new ZenPolicy.Builder().build(), NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); String id = mZenModeHelperSpy.addAutomaticZenRule("android", zenRule, "test"); @@ -1608,6 +1625,107 @@ public class ZenModeHelperTest extends UiServiceTestCase { assertEquals(NotificationManager.zenModeFromInterruptionFilter( zenRule.getInterruptionFilter(), -1), ruleInConfig.zenMode); assertEquals(zenRule.getName(), ruleInConfig.name); + assertEquals("android", ruleInConfig.pkg); + } + + @Test + public void testAddAutomaticZenRule_CPS() { + AutomaticZenRule zenRule = new AutomaticZenRule("name", + new ComponentName("android", "ScheduleConditionProvider"), + ZenModeConfig.toScheduleConditionId(new ScheduleInfo()), + NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); + String id = mZenModeHelperSpy.addAutomaticZenRule("android", zenRule, "test"); + + assertTrue(id != null); + ZenModeConfig.ZenRule ruleInConfig = mZenModeHelperSpy.mConfig.automaticRules.get(id); + assertTrue(ruleInConfig != null); + assertEquals(zenRule.isEnabled(), ruleInConfig.enabled); + assertEquals(zenRule.isModified(), ruleInConfig.modified); + assertEquals(zenRule.getConditionId(), ruleInConfig.conditionId); + assertEquals(NotificationManager.zenModeFromInterruptionFilter( + zenRule.getInterruptionFilter(), -1), ruleInConfig.zenMode); + assertEquals(zenRule.getName(), ruleInConfig.name); + assertEquals("android", ruleInConfig.pkg); + } + + @Test + public void testSetAutomaticZenRuleState_nullPkg() { + AutomaticZenRule zenRule = new AutomaticZenRule("name", + null, + new ComponentName(mContext.getPackageName(), "ScheduleConditionProvider"), + ZenModeConfig.toScheduleConditionId(new ScheduleInfo()), + new ZenPolicy.Builder().build(), + NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); + + String id = mZenModeHelperSpy.addAutomaticZenRule(null, zenRule, "test"); + mZenModeHelperSpy.setAutomaticZenRuleState(zenRule.getConditionId(), + new Condition(zenRule.getConditionId(), "", STATE_TRUE)); + + ZenModeConfig.ZenRule ruleInConfig = mZenModeHelperSpy.mConfig.automaticRules.get(id); + assertEquals(STATE_TRUE, ruleInConfig.condition.state); + } + + @Test + public void testUpdateAutomaticZenRule_nullPkg() { + AutomaticZenRule zenRule = new AutomaticZenRule("name", + null, + new ComponentName(mContext.getPackageName(), "ScheduleConditionProvider"), + ZenModeConfig.toScheduleConditionId(new ScheduleInfo()), + new ZenPolicy.Builder().build(), + NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); + + String id = mZenModeHelperSpy.addAutomaticZenRule(null, zenRule, "test"); + + AutomaticZenRule zenRule2 = new AutomaticZenRule("NEW", + null, + new ComponentName(mContext.getPackageName(), "ScheduleConditionProvider"), + ZenModeConfig.toScheduleConditionId(new ScheduleInfo()), + new ZenPolicy.Builder().build(), + NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); + + mZenModeHelperSpy.updateAutomaticZenRule(id, zenRule2, ""); + + ZenModeConfig.ZenRule ruleInConfig = mZenModeHelperSpy.mConfig.automaticRules.get(id); + assertEquals("NEW", ruleInConfig.name); + } + + @Test + public void testRemoveAutomaticZenRule_nullPkg() { + AutomaticZenRule zenRule = new AutomaticZenRule("name", + null, + new ComponentName(mContext.getPackageName(), "ScheduleConditionProvider"), + ZenModeConfig.toScheduleConditionId(new ScheduleInfo()), + new ZenPolicy.Builder().build(), + NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); + + String id = mZenModeHelperSpy.addAutomaticZenRule(null, zenRule, "test"); + + assertTrue(id != null); + ZenModeConfig.ZenRule ruleInConfig = mZenModeHelperSpy.mConfig.automaticRules.get(id); + assertTrue(ruleInConfig != null); + assertEquals(zenRule.getName(), ruleInConfig.name); + + mZenModeHelperSpy.removeAutomaticZenRule(id, "test"); + assertNull(mZenModeHelperSpy.mConfig.automaticRules.get(id)); + } + + @Test + public void testRemoveAutomaticZenRules_nullPkg() { + AutomaticZenRule zenRule = new AutomaticZenRule("name", + null, + new ComponentName(mContext.getPackageName(), "ScheduleConditionProvider"), + ZenModeConfig.toScheduleConditionId(new ScheduleInfo()), + new ZenPolicy.Builder().build(), + NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); + String id = mZenModeHelperSpy.addAutomaticZenRule(null, zenRule, "test"); + + assertTrue(id != null); + ZenModeConfig.ZenRule ruleInConfig = mZenModeHelperSpy.mConfig.automaticRules.get(id); + assertTrue(ruleInConfig != null); + assertEquals(zenRule.getName(), ruleInConfig.name); + + mZenModeHelperSpy.removeAutomaticZenRules(mContext.getPackageName(), "test"); + assertNull(mZenModeHelperSpy.mConfig.automaticRules.get(id)); } @Test @@ -1624,17 +1742,17 @@ public class ZenModeHelperTest extends UiServiceTestCase { NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); String id2 = mZenModeHelperSpy.addAutomaticZenRule("android", zenRule2, "test"); - Condition condition = new Condition(sharedUri, "", Condition.STATE_TRUE); + Condition condition = new Condition(sharedUri, "", STATE_TRUE); mZenModeHelperSpy.setAutomaticZenRuleState(sharedUri, condition); for (ZenModeConfig.ZenRule rule : mZenModeHelperSpy.mConfig.automaticRules.values()) { if (rule.id.equals(id)) { assertNotNull(rule.condition); - assertTrue(rule.condition.state == Condition.STATE_TRUE); + assertTrue(rule.condition.state == STATE_TRUE); } if (rule.id.equals(id2)) { assertNotNull(rule.condition); - assertTrue(rule.condition.state == Condition.STATE_TRUE); + assertTrue(rule.condition.state == STATE_TRUE); } } diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java index 0a36af2d586a..2df9a8df3a99 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java @@ -348,6 +348,7 @@ public class ActivityStarterTests extends WindowTestsBase { invocation -> { throw new RuntimeException("Not stubbed"); }); + doReturn(null).when(mMockPackageManager).getDefaultHomeActivity(anyInt()); doReturn(mMockPackageManager).when(mAtm).getPackageManagerInternalLocked(); doReturn(false).when(mMockPackageManager).isInstantAppInstallerComponent(any()); doReturn(null).when(mMockPackageManager).resolveIntent(any(), any(), anyInt(), anyInt(), @@ -1135,6 +1136,7 @@ public class ActivityStarterTests extends WindowTestsBase { /* doResume */true, /* options */null, /* inTask */null, + /* inTaskFragment */ null, /* restrictedBgActivity */false, /* intentGrants */null); @@ -1145,6 +1147,31 @@ public class ActivityStarterTests extends WindowTestsBase { } @Test + public void testStartActivityInner_inTaskFragment() { + final ActivityStarter starter = prepareStarter(0, false); + final ActivityRecord targetRecord = new ActivityBuilder(mAtm).build(); + final ActivityRecord sourceRecord = new ActivityBuilder(mAtm).setCreateTask(true).build(); + final TaskFragment taskFragment = new TaskFragment(mAtm, sourceRecord.token, + true /* createdByOrganizer */); + sourceRecord.getTask().addChild(taskFragment, POSITION_TOP); + + starter.startActivityInner( + /* r */targetRecord, + /* sourceRecord */ sourceRecord, + /* voiceSession */null, + /* voiceInteractor */ null, + /* startFlags */ 0, + /* doResume */true, + /* options */null, + /* inTask */null, + /* inTaskFragment */ taskFragment, + /* restrictedBgActivity */false, + /* intentGrants */null); + + assertTrue(taskFragment.hasChild()); + } + + @Test public void testLaunchCookie_newAndExistingTask() { final ActivityStarter starter = prepareStarter(0, false); diff --git a/services/tests/wmtests/src/com/android/server/wm/InputMethodMenuControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InputMethodMenuControllerTest.java index f2418c68358d..a8ede13e5de6 100644 --- a/services/tests/wmtests/src/com/android/server/wm/InputMethodMenuControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/InputMethodMenuControllerTest.java @@ -82,7 +82,7 @@ public class InputMethodMenuControllerTest extends WindowTestsBase { mWm.mWindowContextListenerController.registerWindowContainerListener(clientToken, dc.getImeContainer(), 1000 /* ownerUid */, TYPE_INPUT_METHOD_DIALOG, null /* options */); - return true; + return dc.getImeContainer().getConfiguration(); }).when(wms).attachWindowContextToDisplayArea(any(), eq(TYPE_INPUT_METHOD_DIALOG), anyInt(), any()); diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java index 647a898a5361..609d15937b2e 100644 --- a/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java @@ -200,28 +200,37 @@ public class LetterboxTest { assertTrue(mLetterbox.needsApplySurfaceChanges()); mLetterbox.applySurfaceChanges(mTransaction); - verify(mTransaction).setAlpha(mSurfaces.top, mDarkScrimAlpha); + verify(mTransaction).setAlpha(mSurfaces.fullWindowSurface, mDarkScrimAlpha); } @Test - public void testApplySurfaceChanges_cornersNotRounded_surfaceBehindNotCreated() { + public void testApplySurfaceChanges_cornersNotRounded_surfaceFullWindowSurfaceNotCreated() { mLetterbox.layout(new Rect(0, 0, 10, 10), new Rect(0, 1, 10, 10), new Point(1000, 2000)); mLetterbox.applySurfaceChanges(mTransaction); - assertNull(mSurfaces.behind); + assertNull(mSurfaces.fullWindowSurface); } @Test - public void testApplySurfaceChanges_cornersRounded_surfaceBehindCreated() { + public void testApplySurfaceChanges_cornersRounded_surfaceFullWindowSurfaceCreated() { mAreCornersRounded = true; mLetterbox.layout(new Rect(0, 0, 10, 10), new Rect(0, 1, 10, 10), new Point(1000, 2000)); mLetterbox.applySurfaceChanges(mTransaction); - assertNotNull(mSurfaces.behind); + assertNotNull(mSurfaces.fullWindowSurface); } @Test - public void testNotIntersectsOrFullyContains_cornersRounded_doesNotCheckSurfaceBehind() { + public void testApplySurfaceChanges_wallpaperBackground_surfaceFullWindowSurfaceCreated() { + mHasWallpaperBackground = true; + mLetterbox.layout(new Rect(0, 0, 10, 10), new Rect(0, 1, 10, 10), new Point(1000, 2000)); + mLetterbox.applySurfaceChanges(mTransaction); + + assertNotNull(mSurfaces.fullWindowSurface); + } + + @Test + public void testNotIntersectsOrFullyContains_cornersRounded() { mAreCornersRounded = true; mLetterbox.layout(new Rect(0, 0, 10, 10), new Rect(0, 1, 10, 10), new Point(0, 0)); mLetterbox.applySurfaceChanges(mTransaction); @@ -249,8 +258,8 @@ public class LetterboxTest { public SurfaceControl right; private SurfaceControl.Builder mBottomBuilder; public SurfaceControl bottom; - private SurfaceControl.Builder mBehindBuilder; - public SurfaceControl behind; + private SurfaceControl.Builder mFullWindowSurfaceBuilder; + public SurfaceControl fullWindowSurface; @Override public SurfaceControl.Builder get() { @@ -265,8 +274,8 @@ public class LetterboxTest { mRightBuilder = (SurfaceControl.Builder) i.getMock(); } else if (((String) i.getArgument(0)).contains("bottom")) { mBottomBuilder = (SurfaceControl.Builder) i.getMock(); - } else if (((String) i.getArgument(0)).contains("behind")) { - mBehindBuilder = (SurfaceControl.Builder) i.getMock(); + } else if (((String) i.getArgument(0)).contains("fullWindow")) { + mFullWindowSurfaceBuilder = (SurfaceControl.Builder) i.getMock(); } return i.getMock(); }); @@ -281,8 +290,8 @@ public class LetterboxTest { right = control; } else if (i.getMock() == mBottomBuilder) { bottom = control; - } else if (i.getMock() == mBehindBuilder) { - behind = control; + } else if (i.getMock() == mFullWindowSurfaceBuilder) { + fullWindowSurface = control; } return control; }).when(builder).build(); diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java index a034ac267287..d88fbee6ae13 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java @@ -307,6 +307,29 @@ public class RecentsAnimationControllerTest extends WindowTestsBase { } @Test + public void testBinderDiedAfterCancelWithDeferredScreenshot() throws Exception { + mWm.setRecentsAnimationController(mController); + final ActivityRecord homeActivity = createHomeActivity(); + final ActivityRecord activity = createActivityRecord(mDefaultDisplay); + final WindowState win1 = createWindow(null, TYPE_BASE_APPLICATION, activity, "win1"); + activity.addWindow(win1); + + initializeRecentsAnimationController(mController, homeActivity); + mController.setWillFinishToHome(true); + + // Verify cancel is called with a snapshot and that we've created an overlay + spyOn(mWm.mTaskSnapshotController); + doReturn(mMockTaskSnapshot).when(mWm.mTaskSnapshotController).getSnapshot(anyInt(), + anyInt(), eq(false) /* restoreFromDisk */, eq(false) /* isLowResolution */); + mController.cancelAnimationWithScreenshot(true /* screenshot */); + verify(mMockRunner).onAnimationCanceled(any()); + + // Simulate process crashing and ensure the animation is still canceled + mController.binderDied(); + verify(mAnimationCallbacks).onAnimationFinished(REORDER_KEEP_IN_PLACE, false); + } + + @Test public void testRecentViewInFixedPortraitWhenTopAppInLandscape() { unblockDisplayRotation(mDefaultDisplay); mWm.setRecentsAnimationController(mController); @@ -701,6 +724,12 @@ public class RecentsAnimationControllerTest extends WindowTestsBase { // Continue the animation (simulating a call to cleanupScreenshot()) mController.continueDeferredCancelAnimation(); verify(mAnimationCallbacks).onAnimationFinished(REORDER_MOVE_TO_TOP, false); + + // Assume home was moved to front so will-be-top callback should not be called. + homeActivity.moveFocusableActivityToTop("test"); + spyOn(mDefaultDisplay.mFixedRotationTransitionListener); + mController.cleanupAnimation(REORDER_MOVE_TO_TOP); + verify(mDefaultDisplay.mFixedRotationTransitionListener, never()).notifyRecentsWillBeTop(); } private ActivityRecord createHomeActivity() { diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java index b47e6c1e544f..59894973521d 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java @@ -107,7 +107,8 @@ public class SizeCompatTests extends WindowTestsBase { public void setUp() throws Exception { mInitialConstrainDisplayApisFlags = DeviceConfig.getProperties( NAMESPACE_CONSTRAIN_DISPLAY_APIS); - clearConstrainDisplayApisFlags(); + DeviceConfig.setProperties( + new Properties.Builder(NAMESPACE_CONSTRAIN_DISPLAY_APIS).build()); } @After @@ -597,7 +598,6 @@ public class SizeCompatTests extends WindowTestsBase { verify(mTask).onSizeCompatActivityChanged(); ActivityManager.RunningTaskInfo taskInfo = mTask.getTaskInfo(); - assertEquals(mActivity.appToken, taskInfo.topActivityToken); assertTrue(taskInfo.topActivityInSizeCompat); // Make the activity resizable again by restarting it @@ -613,7 +613,6 @@ public class SizeCompatTests extends WindowTestsBase { verify(mTask).onSizeCompatActivityChanged(); taskInfo = mTask.getTaskInfo(); - assertEquals(mActivity.appToken, taskInfo.topActivityToken); assertFalse(taskInfo.topActivityInSizeCompat); } @@ -632,7 +631,6 @@ public class SizeCompatTests extends WindowTestsBase { verify(mTask).onSizeCompatActivityChanged(); ActivityManager.RunningTaskInfo taskInfo = mTask.getTaskInfo(); - assertEquals(mActivity.appToken, taskInfo.topActivityToken); assertTrue(taskInfo.topActivityInSizeCompat); // Create another Task to hold another size compat activity. @@ -653,7 +651,6 @@ public class SizeCompatTests extends WindowTestsBase { verify(mTask, never()).onSizeCompatActivityChanged(); taskInfo = secondTask.getTaskInfo(); - assertEquals(secondActivity.appToken, taskInfo.topActivityToken); assertTrue(taskInfo.topActivityInSizeCompat); } @@ -925,7 +922,7 @@ public class SizeCompatTests extends WindowTestsBase { @Test @DisableCompatChanges({ActivityInfo.ALWAYS_SANDBOX_DISPLAY_APIS}) - public void testAlwaysSandboxDisplayApis_configDisabled_sandboxingNotApplied() { + public void testAlwaysSandboxDisplayApis_configDisabled_sandboxingApplied() { setUpDisplaySizeWithApp(1000, 1200); // Make the task root resizable. @@ -937,7 +934,7 @@ public class SizeCompatTests extends WindowTestsBase { activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); prepareUnresizable(activity, /* maxAspect=*/ 1.5f, SCREEN_ORIENTATION_LANDSCAPE); - // Activity max bounds be sandboxed due to letterbox and the config being disabled. + // Activity max bounds should be sandboxed due to letterbox and the config being disabled. assertActivityMaxBoundsSandboxed(activity); } @@ -967,6 +964,27 @@ public class SizeCompatTests extends WindowTestsBase { } @Test + public void testAlwaysConstrainDisplayApisDeviceConfig_packageInRange_sandboxingApplied() { + setUpDisplaySizeWithApp(1000, 1200); + + setAlwaysConstrainDisplayApisFlag( + "com.android.frameworks.wmtests:20:,com.android.other::," + + "com.android.frameworks.wmtests:0:10"); + + // Make the task root resizable. + mActivity.info.resizeMode = RESIZE_MODE_RESIZEABLE; + + // Create an activity with a max aspect ratio on the same task. + final ActivityRecord activity = buildActivityRecord(/* supportsSizeChanges= */false, + RESIZE_MODE_UNRESIZEABLE, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); + activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + prepareUnresizable(activity, /* maxAspect=*/ 1.5f, SCREEN_ORIENTATION_LANDSCAPE); + + // Resizable activity is sandboxed due to match with flag. + assertActivityMaxBoundsSandboxed(activity); + } + + @Test @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO, ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM}) public void testOverrideMinAspectRatioMedium() { @@ -2146,8 +2164,8 @@ public class SizeCompatTests extends WindowTestsBase { value, /* makeDefault= */ false); } - private static void clearConstrainDisplayApisFlags() { - setNeverConstrainDisplayApisFlag(null); - setNeverConstrainDisplayApisAllPackagesFlag(null); + private static void setAlwaysConstrainDisplayApisFlag(@Nullable String value) { + DeviceConfig.setProperty(NAMESPACE_CONSTRAIN_DISPLAY_APIS, "always_constrain_display_apis", + value, /* makeDefault= */ false); } } diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java new file mode 100644 index 000000000000..6bd8ad27342a --- /dev/null +++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.wm; + +import static android.window.TaskFragmentOrganizer.putExceptionInBundle; + +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; +import static com.android.server.wm.testing.Assert.assertThrows; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.clearInvocations; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + +import android.content.res.Configuration; +import android.os.Binder; +import android.os.Bundle; +import android.os.IBinder; +import android.os.RemoteException; +import android.platform.test.annotations.Presubmit; +import android.view.SurfaceControl; +import android.window.ITaskFragmentOrganizer; +import android.window.TaskFragmentInfo; +import android.window.TaskFragmentOrganizer; + +import androidx.test.filters.SmallTest; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Build/Install/Run: + * atest WmTests:TaskFragmentOrganizerControllerTest + */ +@SmallTest +@Presubmit +@RunWith(WindowTestRunner.class) +public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { + + private TaskFragmentOrganizerController mController; + private TaskFragmentOrganizer mOrganizer; + private ITaskFragmentOrganizer mIOrganizer; + private TaskFragment mTaskFragment; + private TaskFragmentInfo mTaskFragmentInfo; + private IBinder mFragmentToken; + + @Before + public void setup() { + mController = mWm.mAtmService.mWindowOrganizerController.mTaskFragmentOrganizerController; + mOrganizer = new TaskFragmentOrganizer(Runnable::run); + mIOrganizer = mOrganizer.getIOrganizer(); + mTaskFragment = mock(TaskFragment.class); + mTaskFragmentInfo = mock(TaskFragmentInfo.class); + mFragmentToken = new Binder(); + + spyOn(mController); + spyOn(mOrganizer); + doReturn(mIOrganizer).when(mTaskFragment).getTaskFragmentOrganizer(); + doReturn(mTaskFragmentInfo).when(mTaskFragment).getTaskFragmentInfo(); + doReturn(new SurfaceControl()).when(mTaskFragment).getSurfaceControl(); + doReturn(mFragmentToken).when(mTaskFragment).getFragmentToken(); + doReturn(new Configuration()).when(mTaskFragmentInfo).getConfiguration(); + } + + @Test + public void testCallTaskFragmentCallbackWithoutRegister_throwsException() { + assertThrows(IllegalArgumentException.class, () -> mController + .onTaskFragmentAppeared(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment)); + + assertThrows(IllegalArgumentException.class, () -> mController + .onTaskFragmentInfoChanged( + mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment)); + + assertThrows(IllegalArgumentException.class, () -> mController + .onTaskFragmentVanished(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment)); + + assertThrows(IllegalArgumentException.class, () -> mController + .onTaskFragmentParentInfoChanged(mTaskFragment.getTaskFragmentOrganizer(), + mTaskFragment)); + } + + @Test + public void testOnTaskFragmentAppeared() { + mController.registerOrganizer(mIOrganizer); + + mController.onTaskFragmentAppeared(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment); + + verify(mOrganizer).onTaskFragmentAppeared(any()); + } + + @Test + public void testOnTaskFragmentInfoChanged() { + mController.registerOrganizer(mIOrganizer); + mController.onTaskFragmentAppeared(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment); + + // No callback if the info is not changed. + doReturn(true).when(mTaskFragmentInfo).equalsForTaskFragmentOrganizer(any()); + doReturn(new Configuration()).when(mTaskFragmentInfo).getConfiguration(); + + mController.onTaskFragmentInfoChanged(mTaskFragment.getTaskFragmentOrganizer(), + mTaskFragment); + + verify(mOrganizer, never()).onTaskFragmentInfoChanged(any()); + + // Trigger callback if the info is changed. + doReturn(false).when(mTaskFragmentInfo).equalsForTaskFragmentOrganizer(any()); + + mController.onTaskFragmentInfoChanged(mTaskFragment.getTaskFragmentOrganizer(), + mTaskFragment); + + verify(mOrganizer).onTaskFragmentInfoChanged(mTaskFragmentInfo); + } + + @Test + public void testOnTaskFragmentVanished() { + mController.registerOrganizer(mIOrganizer); + + mController.onTaskFragmentVanished(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment); + + verify(mOrganizer).onTaskFragmentVanished(any()); + } + + @Test + public void testOnTaskFragmentParentInfoChanged() { + mController.registerOrganizer(mIOrganizer); + final Task parent = mock(Task.class); + final Configuration parentConfig = new Configuration(); + parentConfig.smallestScreenWidthDp = 10; + doReturn(parent).when(mTaskFragment).getParent(); + doReturn(parentConfig).when(parent).getConfiguration(); + doReturn(parent).when(parent).asTask(); + + mController.onTaskFragmentParentInfoChanged( + mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment); + + verify(mOrganizer).onTaskFragmentParentInfoChanged(eq(mFragmentToken), any()); + + // No extra callback if the info is not changed. + clearInvocations(mOrganizer); + + mController.onTaskFragmentParentInfoChanged( + mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment); + + verify(mOrganizer, never()).onTaskFragmentParentInfoChanged(any(), any()); + + // Trigger callback if the info is changed. + parentConfig.smallestScreenWidthDp = 100; + + mController.onTaskFragmentParentInfoChanged( + mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment); + + verify(mOrganizer).onTaskFragmentParentInfoChanged(eq(mFragmentToken), any()); + } + + @Test + public void testOnTaskFragmentError() throws RemoteException { + final IBinder errorCallbackToken = new Binder(); + final Throwable exception = new IllegalArgumentException("Test exception"); + final Bundle exceptionBundle = putExceptionInBundle(exception); + + mIOrganizer.onTaskFragmentError(errorCallbackToken, exceptionBundle); + + verify(mOrganizer).onTaskFragmentError(eq(errorCallbackToken), eq(exception)); + } +} diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java index 2dfb3a1a84bc..45e5f8e55f8a 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java @@ -339,6 +339,44 @@ public class TransitionTests extends WindowTestsBase { } @Test + public void testTargets_noIntermediatesToWallpaper() { + final Transition transition = createTestTransition(TRANSIT_OLD_TASK_OPEN); + + final WallpaperWindowToken wallpaperWindowToken = new WallpaperWindowToken(mWm, + mock(IBinder.class), true, mDisplayContent, true /* ownerCanManageAppTokens */); + // Make DA organized so we can check that they don't get included. + WindowContainer parent = wallpaperWindowToken.getParent(); + while (parent != null && parent != mDisplayContent) { + if (parent.asDisplayArea() != null) { + parent.asDisplayArea().setOrganizer( + mock(android.window.IDisplayAreaOrganizer.class), true /* skipAppear */); + } + parent = parent.getParent(); + } + final WindowState wallpaperWindow = createWindow(null, TYPE_WALLPAPER, wallpaperWindowToken, + "wallpaperWindow"); + wallpaperWindowToken.setVisibleRequested(false); + transition.collect(wallpaperWindowToken); + wallpaperWindowToken.setVisibleRequested(true); + wallpaperWindow.mHasSurface = true; + doReturn(true).when(mDisplayContent).isAttached(); + transition.collect(mDisplayContent); + mDisplayContent.getWindowConfiguration().setRotation( + (mDisplayContent.getWindowConfiguration().getRotation() + 1) % 4); + + ArraySet<WindowContainer> targets = Transition.calculateTargets( + transition.mParticipants, transition.mChanges); + TransitionInfo info = Transition.calculateTransitionInfo( + 0, 0, targets, transition.mChanges); + // The wallpaper is not organized, so it won't have a token; however, it will be marked + // as IS_WALLPAPER + assertEquals(FLAG_IS_WALLPAPER, info.getChanges().get(0).getFlags()); + // Make sure no intermediate display areas were pulled in between wallpaper and display. + assertEquals(mDisplayContent.mRemoteToken.toWindowContainerToken(), + info.getChanges().get(0).getParent()); + } + + @Test public void testIndependent() { final Transition transition = createTestTransition(TRANSIT_OPEN); ArrayMap<WindowContainer, Transition.ChangeInfo> changes = transition.mChanges; diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java index d9aa871447be..83cdc3ba3ebd 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java @@ -107,9 +107,9 @@ public class WindowManagerServiceTests extends WindowTestsBase { Task tappedTask = createTaskInRootTask(tappedRootTask, 0 /* userId */); spyOn(mWm.mAtmService); - mWm.handleTaskFocusChange(tappedTask); + mWm.handleTaskFocusChange(tappedTask, null /* window */); - verify(mWm.mAtmService).setFocusedTask(tappedTask.mTaskId); + verify(mWm.mAtmService).setFocusedTask(tappedTask.mTaskId, null); } @Test @@ -128,9 +128,9 @@ public class WindowManagerServiceTests extends WindowTestsBase { Task tappedTask = createTaskInRootTask(tappedRootTask, 0 /* userId */); spyOn(mWm.mAtmService); - mWm.handleTaskFocusChange(tappedTask); + mWm.handleTaskFocusChange(tappedTask, null /* window */); - verify(mWm.mAtmService, never()).setFocusedTask(tappedTask.mTaskId); + verify(mWm.mAtmService, never()).setFocusedTask(tappedTask.mTaskId, null); } @Test @@ -151,9 +151,9 @@ public class WindowManagerServiceTests extends WindowTestsBase { Task tappedTask = createTaskInRootTask(tappedRootTask, 0 /* userId */); spyOn(mWm.mAtmService); - mWm.handleTaskFocusChange(tappedTask); + mWm.handleTaskFocusChange(tappedTask, null /* window */); - verify(mWm.mAtmService).setFocusedTask(tappedTask.mTaskId); + verify(mWm.mAtmService).setFocusedTask(tappedTask.mTaskId, null); } @Test diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java index 8fa7101dd05a..39fe952cc199 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java @@ -61,6 +61,7 @@ import static org.mockito.Mockito.clearInvocations; import android.app.ActivityManager; import android.app.ActivityManager.RunningTaskInfo; +import android.app.ActivityOptions; import android.app.ActivityTaskManager.RootTaskInfo; import android.app.IRequestFinishCallback; import android.app.PictureInPictureParams; @@ -69,7 +70,6 @@ import android.content.pm.ParceledListSlice; import android.content.res.Configuration; import android.graphics.Rect; import android.os.Binder; -import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.platform.test.annotations.Presubmit; @@ -1228,7 +1228,6 @@ public class WindowOrganizerTests extends WindowTestsBase { verify(organizer).onTaskInfoChanged(infoCaptor.capture()); RunningTaskInfo info = infoCaptor.getValue(); assertEquals(rootTask.mTaskId, info.taskId); - assertEquals(activity.appToken, info.topActivityToken); assertTrue(info.topActivityInSizeCompat); // Ensure task info show top activity that is not in foreground as not in size compat. @@ -1239,7 +1238,6 @@ public class WindowOrganizerTests extends WindowTestsBase { verify(organizer).onTaskInfoChanged(infoCaptor.capture()); info = infoCaptor.getValue(); assertEquals(rootTask.mTaskId, info.taskId); - assertEquals(activity.appToken, info.topActivityToken); assertFalse(info.topActivityInSizeCompat); // Ensure task info show non size compat top activity as not in size compat. @@ -1251,28 +1249,30 @@ public class WindowOrganizerTests extends WindowTestsBase { verify(organizer).onTaskInfoChanged(infoCaptor.capture()); info = infoCaptor.getValue(); assertEquals(rootTask.mTaskId, info.taskId); - assertEquals(activity.appToken, info.topActivityToken); assertFalse(info.topActivityInSizeCompat); } @Test public void testStartTasksInTransaction() { WindowContainerTransaction wct = new WindowContainerTransaction(); - Bundle testOptions = new Bundle(); - testOptions.putInt("test", 20); + ActivityOptions testOptions = ActivityOptions.makeBasic(); + testOptions.setTransientLaunch(); wct.startTask(1, null /* options */); - wct.startTask(2, testOptions); - spyOn(mWm.mAtmService); - doReturn(START_CANCELED).when(mWm.mAtmService).startActivityFromRecents(anyInt(), any()); + wct.startTask(2, testOptions.toBundle()); + spyOn(mWm.mAtmService.mTaskSupervisor); + doReturn(START_CANCELED).when(mWm.mAtmService.mTaskSupervisor).startActivityFromRecents( + anyInt(), anyInt(), anyInt(), any()); clearInvocations(mWm.mAtmService); mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct); - final ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class); - verify(mWm.mAtmService, times(1)).startActivityFromRecents(eq(1), bundleCaptor.capture()); - assertTrue(bundleCaptor.getValue().isEmpty()); + verify(mWm.mAtmService.mTaskSupervisor, times(1)).startActivityFromRecents( + anyInt(), anyInt(), eq(1), any()); - verify(mWm.mAtmService, times(1)).startActivityFromRecents(eq(2), bundleCaptor.capture()); - assertEquals(20, bundleCaptor.getValue().getInt("test")); + final ArgumentCaptor<SafeActivityOptions> optionsCaptor = + ArgumentCaptor.forClass(SafeActivityOptions.class); + verify(mWm.mAtmService.mTaskSupervisor, times(1)).startActivityFromRecents( + anyInt(), anyInt(), eq(2), optionsCaptor.capture()); + assertTrue(optionsCaptor.getValue().getOriginalOptions().getTransientLaunch()); } /** diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java index 1240f9ba84a0..d3f2d1407a46 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java @@ -34,6 +34,8 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; @@ -366,6 +368,15 @@ public class WindowProcessControllerTests extends WindowTestsBase { } @Test + public void testTopActivityUiModeChangeScheduleConfigChange() { + final ActivityRecord activity = createActivityRecord(mWpc); + activity.mVisibleRequested = true; + doReturn(true).when(activity).setOverrideNightMode(anyInt()); + mWpc.updateNightModeForAllActivities(Configuration.UI_MODE_NIGHT_YES); + verify(activity).ensureActivityConfiguration(anyInt(), anyBoolean()); + } + + @Test public void testTopActivityDisplayAreaMatchesTopMostActivity_noActivities() { assertNull(mWpc.getTopActivityDisplayArea()); } diff --git a/services/usb/java/com/android/server/usb/UsbPortManager.java b/services/usb/java/com/android/server/usb/UsbPortManager.java index d6c046921c57..ec28040f82d8 100644 --- a/services/usb/java/com/android/server/usb/UsbPortManager.java +++ b/services/usb/java/com/android/server/usb/UsbPortManager.java @@ -385,29 +385,16 @@ public class UsbPortManager { * @param none */ private void updateUsbHalVersion() { - android.hardware.usb.V1_3.IUsb usbProxy_V1_3 = - android.hardware.usb.V1_3.IUsb.castFrom(mProxy); - if (usbProxy_V1_3 != null) { + if (android.hardware.usb.V1_3.IUsb.castFrom(mProxy) != null) { mCurrentUsbHalVersion = UsbManager.USB_HAL_V1_3; - return; - } - - android.hardware.usb.V1_2.IUsb usbProxy_V1_2 = - android.hardware.usb.V1_2.IUsb.castFrom(mProxy); - if (usbProxy_V1_2 != null) { + } else if (android.hardware.usb.V1_2.IUsb.castFrom(mProxy) != null) { mCurrentUsbHalVersion = UsbManager.USB_HAL_V1_2; - return; - } - - android.hardware.usb.V1_1.IUsb usbProxy_V1_1 = - android.hardware.usb.V1_1.IUsb.castFrom(mProxy); - if (usbProxy_V1_1 != null) { + } else if (android.hardware.usb.V1_1.IUsb.castFrom(mProxy) != null) { mCurrentUsbHalVersion = UsbManager.USB_HAL_V1_1; - return; + } else { + mCurrentUsbHalVersion = UsbManager.USB_HAL_V1_0; } - - mCurrentUsbHalVersion = UsbManager.USB_HAL_V1_0; - return; + logAndPrint(Log.INFO, null, "USB HAL version: " + mCurrentUsbHalVersion); } public void setPortRoles(String portId, int newPowerRole, int newDataRole, @@ -850,7 +837,7 @@ public class UsbPortManager { mProxy.linkToDeath(new DeathRecipient(pw), USB_HAL_DEATH_COOKIE); mProxy.setCallback(mHALCallback); mProxy.queryPortStatus(); - mCurrentUsbHalVersion = UsbManager.USB_HAL_V1_0; + updateUsbHalVersion(); } catch (NoSuchElementException e) { logAndPrintException(pw, "connectToProxy: usb hal service not found." + " Did the service fail to start?", e); @@ -1183,7 +1170,6 @@ public class UsbPortManager { case MSG_SYSTEM_READY: { mNotificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); - updateUsbHalVersion(); break; } } diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java index 666265e55372..e408cfc77ad0 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java @@ -16,20 +16,28 @@ package com.android.server.voiceinteraction; +import static android.Manifest.permission.CAPTURE_AUDIO_HOTWORD; +import static android.Manifest.permission.RECORD_AUDIO; import static android.service.voice.HotwordDetectionService.AUDIO_SOURCE_EXTERNAL; import static android.service.voice.HotwordDetectionService.AUDIO_SOURCE_MICROPHONE; import static android.service.voice.HotwordDetectionService.INITIALIZATION_STATUS_UNKNOWN; import static android.service.voice.HotwordDetectionService.KEY_INITIALIZATION_STATUS; +import static com.android.server.voiceinteraction.SoundTriggerSessionPermissionsDecorator.enforcePermissionForPreflight; + import android.annotation.NonNull; import android.annotation.Nullable; +import android.app.AppOpsManager; import android.content.ComponentName; import android.content.ContentCaptureOptions; import android.content.Context; import android.content.Intent; +import android.content.PermissionChecker; import android.hardware.soundtrigger.IRecognitionStatusCallback; import android.hardware.soundtrigger.SoundTrigger; import android.media.AudioFormat; +import android.media.permission.Identity; +import android.media.permission.PermissionUtil; import android.os.Binder; import android.os.Bundle; import android.os.IBinder; @@ -46,6 +54,7 @@ import android.service.voice.IDspHotwordDetectionCallback; import android.service.voice.IHotwordDetectionService; import android.service.voice.IMicrophoneHotwordDetectionVoiceInteractionCallback; import android.service.voice.VoiceInteractionManagerInternal.HotwordDetectionServiceIdentity; +import android.text.TextUtils; import android.util.Pair; import android.util.Slog; import android.view.contentcapture.IContentCaptureManager; @@ -107,6 +116,10 @@ final class HotwordDetectionConnection { private ScheduledFuture<?> mCancellationTaskFuture; + /** Identity used for attributing app ops when delivering data to the Interactor. */ + @GuardedBy("mLock") + @Nullable + private final Identity mVoiceInteractorIdentity; @GuardedBy("mLock") private ParcelFileDescriptor mCurrentAudioSink; @GuardedBy("mLock") @@ -117,12 +130,13 @@ final class HotwordDetectionConnection { private IBinder mAudioFlinger; HotwordDetectionConnection(Object lock, Context context, int voiceInteractionServiceUid, - ComponentName serviceName, int userId, boolean bindInstantServiceAllowed, - @Nullable PersistableBundle options, @Nullable SharedMemory sharedMemory, - IHotwordRecognitionStatusCallback callback) { + Identity voiceInteractorIdentity, ComponentName serviceName, int userId, + boolean bindInstantServiceAllowed, @Nullable PersistableBundle options, + @Nullable SharedMemory sharedMemory, IHotwordRecognitionStatusCallback callback) { mLock = lock; mContext = context; mVoiceInteractionServiceUid = voiceInteractionServiceUid; + mVoiceInteractorIdentity = voiceInteractorIdentity; mDetectionComponentName = serviceName; mUser = userId; final Intent intent = new Intent(HotwordDetectionService.SERVICE_INTERFACE); @@ -310,6 +324,7 @@ final class HotwordDetectionConnection { } synchronized (mLock) { if (mPerformingSoftwareHotwordDetection) { + enforcePermissionsForDataDelivery(); mSoftwareCallback.onDetected(result, null, null); mPerformingSoftwareHotwordDetection = false; if (result != null) { @@ -404,6 +419,7 @@ final class HotwordDetectionConnection { synchronized (mLock) { if (mValidatingDspTrigger) { mValidatingDspTrigger = false; + enforcePermissionsForDataDelivery(); externalCallback.onKeyphraseDetected(recognitionEvent, result); if (result != null) { Slog.i(TAG, "Egressed " + HotwordDetectedResult.getUsageSize(result) @@ -461,6 +477,7 @@ final class HotwordDetectionConnection { return; } mValidatingDspTrigger = false; + enforcePermissionsForDataDelivery(); externalCallback.onKeyphraseDetected(recognitionEvent, result); if (result != null) { Slog.i(TAG, "Egressed " + HotwordDetectedResult.getUsageSize(result) @@ -575,8 +592,7 @@ final class HotwordDetectionConnection { if (DEBUG) { Slog.d(TAG, "onKeyphraseDetected recognitionEvent : " + recognitionEvent); } - final boolean useHotwordDetectionService = mHotwordDetectionConnection != null - && mHotwordDetectionConnection.isBound(); + final boolean useHotwordDetectionService = mHotwordDetectionConnection != null; if (useHotwordDetectionService) { mRecognitionEvent = recognitionEvent; mHotwordDetectionConnection.detectFromDspSource( @@ -692,7 +708,7 @@ final class HotwordDetectionConnection { throws RemoteException { bestEffortClose(serviceAudioSink); bestEffortClose(serviceAudioSource); - // TODO: noteOp here. + enforcePermissionsForDataDelivery(); callback.onDetected(triggerResult, null /* audioFormat */, null /* audioStream */); if (triggerResult != null) { @@ -872,4 +888,42 @@ final class HotwordDetectionConnection { } } } + + // TODO: Share this code with SoundTriggerMiddlewarePermission. + private void enforcePermissionsForDataDelivery() { + Binder.withCleanCallingIdentity(() -> { + enforcePermissionForPreflight(mContext, mVoiceInteractorIdentity, RECORD_AUDIO); + int hotwordOp = AppOpsManager.strOpToOp(AppOpsManager.OPSTR_RECORD_AUDIO_HOTWORD); + mContext.getSystemService(AppOpsManager.class).noteOpNoThrow(hotwordOp, + mVoiceInteractorIdentity.uid, mVoiceInteractorIdentity.packageName, + mVoiceInteractorIdentity.attributionTag, OP_MESSAGE); + enforcePermissionForDataDelivery(mContext, mVoiceInteractorIdentity, + CAPTURE_AUDIO_HOTWORD, OP_MESSAGE); + }); + } + + /** + * Throws a {@link SecurityException} iff the given identity has given permission to receive + * data. + * + * @param context A {@link Context}, used for permission checks. + * @param identity The identity to check. + * @param permission The identifier of the permission we want to check. + * @param reason The reason why we're requesting the permission, for auditing purposes. + */ + private static void enforcePermissionForDataDelivery(@NonNull Context context, + @NonNull Identity identity, + @NonNull String permission, @NonNull String reason) { + final int status = PermissionUtil.checkPermissionForDataDelivery(context, identity, + permission, reason); + if (status != PermissionChecker.PERMISSION_GRANTED) { + throw new SecurityException( + TextUtils.formatSimple("Failed to obtain permission %s for identity %s", + permission, + SoundTriggerSessionPermissionsDecorator.toString(identity))); + } + } + + private static final String OP_MESSAGE = + "Providing hotword detection result to VoiceInteractionService"; }; diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerSessionPermissionsDecorator.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerSessionPermissionsDecorator.java index bb7ca168fcaa..b9e1fcd7ffd3 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerSessionPermissionsDecorator.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerSessionPermissionsDecorator.java @@ -124,7 +124,7 @@ final class SoundTriggerSessionPermissionsDecorator implements * @param identity The identity to check. * @param permission The identifier of the permission we want to check. */ - private static void enforcePermissionForPreflight(@NonNull Context context, + static void enforcePermissionForPreflight(@NonNull Context context, @NonNull Identity identity, @NonNull String permission) { final int status = PermissionUtil.checkPermissionForPreflight(context, identity, permission); @@ -144,7 +144,7 @@ final class SoundTriggerSessionPermissionsDecorator implements } } - private static String toString(Identity identity) { + static String toString(Identity identity) { return "{uid=" + identity.uid + " pid=" + identity.pid + " packageName=" + identity.packageName diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java index 91d17f74c676..ccf4267a0fbc 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java @@ -1101,8 +1101,11 @@ public class VoiceInteractionManagerService extends SystemService { //----------------- Hotword Detection/Validation APIs --------------------------------// @Override - public void updateState(@Nullable PersistableBundle options, - @Nullable SharedMemory sharedMemory, IHotwordRecognitionStatusCallback callback) { + public void updateState( + @NonNull Identity voiceInteractorIdentity, + @Nullable PersistableBundle options, + @Nullable SharedMemory sharedMemory, + IHotwordRecognitionStatusCallback callback) { enforceCallingPermission(Manifest.permission.MANAGE_HOTWORD_DETECTION); synchronized (this) { enforceIsCurrentVoiceInteractionService(); @@ -1111,9 +1114,14 @@ public class VoiceInteractionManagerService extends SystemService { Slog.w(TAG, "updateState without running voice interaction service"); return; } + + voiceInteractorIdentity.uid = Binder.getCallingUid(); + voiceInteractorIdentity.pid = Binder.getCallingPid(); + final long caller = Binder.clearCallingIdentity(); try { - mImpl.updateStateLocked(options, sharedMemory, callback); + mImpl.updateStateLocked( + voiceInteractorIdentity, options, sharedMemory, callback); } finally { Binder.restoreCallingIdentity(caller); } diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java index 89c5a720ee7e..6be47e171ed7 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java @@ -42,6 +42,7 @@ import android.content.pm.ServiceInfo; import android.hardware.soundtrigger.IRecognitionStatusCallback; import android.hardware.soundtrigger.SoundTrigger; import android.media.AudioFormat; +import android.media.permission.Identity; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; @@ -405,8 +406,11 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne return mInfo.getSupportsLocalInteraction(); } - public void updateStateLocked(@Nullable PersistableBundle options, - @Nullable SharedMemory sharedMemory, IHotwordRecognitionStatusCallback callback) { + public void updateStateLocked( + @NonNull Identity voiceInteractorIdentity, + @Nullable PersistableBundle options, + @Nullable SharedMemory sharedMemory, + IHotwordRecognitionStatusCallback callback) { if (DEBUG) { Slog.d(TAG, "updateStateLocked"); } @@ -447,8 +451,9 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne if (mHotwordDetectionConnection == null) { mHotwordDetectionConnection = new HotwordDetectionConnection(mServiceStub, mContext, - mInfo.getServiceInfo().applicationInfo.uid, mHotwordDetectionComponentName, - mUser, /* bindInstantServiceAllowed= */ false, options, sharedMemory, callback); + mInfo.getServiceInfo().applicationInfo.uid, voiceInteractorIdentity, + mHotwordDetectionComponentName, mUser, /* bindInstantServiceAllowed= */ false, + options, sharedMemory, callback); } else { mHotwordDetectionConnection.updateStateLocked(options, sharedMemory); } diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java index 7ba6f36d28e2..53922ed27c10 100644 --- a/telephony/java/android/telephony/ims/ImsMmTelManager.java +++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java @@ -37,6 +37,7 @@ import android.telephony.ims.aidl.IImsCapabilityCallback; import android.telephony.ims.feature.ImsFeature; import android.telephony.ims.feature.MmTelFeature; import android.telephony.ims.stub.ImsRegistrationImplBase; +import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.IIntegerConsumer; @@ -447,8 +448,9 @@ public class ImsMmTelManager implements RegistrationManager { executor.execute(() -> stateCallback.accept(result)); } }); - } catch (RemoteException e) { - throw e.rethrowAsRuntimeException(); + } catch (ServiceSpecificException | RemoteException e) { + Log.w("ImsMmTelManager", "Error getting registration state: " + e); + executor.execute(() -> stateCallback.accept(REGISTRATION_STATE_NOT_REGISTERED)); } } @@ -488,8 +490,10 @@ public class ImsMmTelManager implements RegistrationManager { executor.execute(() -> transportTypeCallback.accept(result)); } }); - } catch (RemoteException e) { - throw e.rethrowAsRuntimeException(); + } catch (ServiceSpecificException | RemoteException e) { + Log.w("ImsMmTelManager", "Error getting transport type: " + e); + executor.execute(() -> transportTypeCallback.accept( + AccessNetworkConstants.TRANSPORT_TYPE_INVALID)); } } diff --git a/telephony/java/android/telephony/ims/ImsRcsManager.java b/telephony/java/android/telephony/ims/ImsRcsManager.java index 370002634278..91c53244a780 100644 --- a/telephony/java/android/telephony/ims/ImsRcsManager.java +++ b/telephony/java/android/telephony/ims/ImsRcsManager.java @@ -302,8 +302,10 @@ public class ImsRcsManager { executor.execute(() -> stateCallback.accept(result)); } }); - } catch (RemoteException e) { - throw e.rethrowAsRuntimeException(); + } catch (ServiceSpecificException | RemoteException e) { + Log.w(TAG, "Get registration state error: " + e); + executor.execute(() -> stateCallback.accept( + RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED)); } } @@ -346,8 +348,10 @@ public class ImsRcsManager { executor.execute(() -> transportTypeCallback.accept(result)); } }); - } catch (RemoteException e) { - throw e.rethrowAsRuntimeException(); + } catch (ServiceSpecificException | RemoteException e) { + Log.w(TAG, "Get registration transport type error: " + e); + executor.execute(() -> transportTypeCallback.accept( + AccessNetworkConstants.TRANSPORT_TYPE_INVALID)); } } diff --git a/tests/StagedInstallTest/Android.bp b/tests/StagedInstallTest/Android.bp index c563e06ab528..1aa04996f682 100644 --- a/tests/StagedInstallTest/Android.bp +++ b/tests/StagedInstallTest/Android.bp @@ -33,6 +33,8 @@ android_test_helper_app { java_resources: [ ":com.android.apex.apkrollback.test_v2", ":StagedInstallTestApexV2_WrongSha", + ":test.rebootless_apex_v1", + ":test.rebootless_apex_v2", ], } @@ -54,6 +56,7 @@ java_test_host { ":com.android.apex.cts.shim.v2_prebuilt", ":StagedInstallTestApexV2_WrongSha", ":TestAppAv1", + ":test.rebootless_apex_v1", ], test_suites: ["general-tests"], test_config: "StagedInstallInternalTest.xml", diff --git a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java index 6a62304f9af7..9cdaef75c491 100644 --- a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java +++ b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java @@ -23,7 +23,10 @@ import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; import android.Manifest; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; import android.content.pm.PackageInstaller; +import android.content.pm.PackageManager; import androidx.test.platform.app.InstrumentationRegistry; @@ -192,6 +195,68 @@ public class StagedInstallInternalTest { assertSessionFailedWithMessage(sessionId, "has unexpected SHA512 hash"); } + @Test + public void testRebootlessUpdates() throws Exception { + InstallUtils.dropShellPermissionIdentity(); + InstallUtils.adoptShellPermissionIdentity(Manifest.permission.INSTALL_PACKAGE_UPDATES); + + final PackageManager pm = + InstrumentationRegistry.getInstrumentation().getContext().getPackageManager(); + { + PackageInfo apex = pm.getPackageInfo("test.apex.rebootless", PackageManager.MATCH_APEX); + assertThat(apex.getLongVersionCode()).isEqualTo(1); + assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) + .isEqualTo(ApplicationInfo.FLAG_SYSTEM); + assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) + .isEqualTo(ApplicationInfo.FLAG_INSTALLED); + assertThat(apex.applicationInfo.sourceDir).startsWith("/system/apex"); + } + + TestApp apex1 = new TestApp("TestRebootlessApexV1", "test.apex.rebootless", 1, + /* isApex= */ true, "test.rebootless_apex_v1.apex"); + Install.single(apex1).commit(); + + { + PackageInfo apex = pm.getPackageInfo("test.apex.rebootless", PackageManager.MATCH_APEX); + assertThat(apex.getLongVersionCode()).isEqualTo(1); + assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM).isEqualTo(0); + assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) + .isEqualTo(ApplicationInfo.FLAG_INSTALLED); + assertThat(apex.applicationInfo.sourceDir).startsWith("/data/apex/active"); + } + { + PackageInfo apex = pm.getPackageInfo("test.apex.rebootless", + PackageManager.MATCH_APEX | PackageManager.MATCH_FACTORY_ONLY); + assertThat(apex.getLongVersionCode()).isEqualTo(1); + assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) + .isEqualTo(ApplicationInfo.FLAG_SYSTEM); + assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED).isEqualTo(0); + assertThat(apex.applicationInfo.sourceDir).startsWith("/system/apex"); + } + + TestApp apex2 = new TestApp("TestRebootlessApexV1", "test.apex.rebootless", 2, + /* isApex= */ true, "test.rebootless_apex_v2.apex"); + Install.single(apex2).commit(); + + { + PackageInfo apex = pm.getPackageInfo("test.apex.rebootless", PackageManager.MATCH_APEX); + assertThat(apex.getLongVersionCode()).isEqualTo(2); + assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM).isEqualTo(0); + assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) + .isEqualTo(ApplicationInfo.FLAG_INSTALLED); + assertThat(apex.applicationInfo.sourceDir).startsWith("/data/apex/active"); + } + { + PackageInfo apex = pm.getPackageInfo("test.apex.rebootless", + PackageManager.MATCH_APEX | PackageManager.MATCH_FACTORY_ONLY); + assertThat(apex.getLongVersionCode()).isEqualTo(1); + assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) + .isEqualTo(ApplicationInfo.FLAG_SYSTEM); + assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED).isEqualTo(0); + assertThat(apex.applicationInfo.sourceDir).startsWith("/system/apex"); + } + } + private static void assertSessionFailedWithMessage(int sessionId, String msg) { assertSessionState(sessionId, (session) -> { assertThat(session.isStagedSessionFailed()).isTrue(); diff --git a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java index 5d7fdd183dec..e19f97b6c045 100644 --- a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java +++ b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java @@ -85,7 +85,9 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test { } deleteFiles("/system/apex/" + APK_IN_APEX_TESTAPEX_NAME + "*.apex", "/data/apex/active/" + APK_IN_APEX_TESTAPEX_NAME + "*.apex", - "/data/apex/active/" + SHIM_APEX_PACKAGE_NAME + "*.apex"); + "/data/apex/active/" + SHIM_APEX_PACKAGE_NAME + "*.apex", + "/system/apex/test.rebootless_apex_v1.apex", + "/data/apex/active/test.apex.rebootless*.apex"); } @Before @@ -124,9 +126,8 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test { } } - private void pushTestApex() throws Exception { + private void pushTestApex(String fileName) throws Exception { CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(getBuild()); - final String fileName = APK_IN_APEX_TESTAPEX_NAME + "_v1.apex"; final File apex = buildHelper.getTestFile(fileName); if (!getDevice().isAdbRoot()) { getDevice().enableAdbRoot(); @@ -142,7 +143,7 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test { @Test @LargeTest public void testDuplicateApkInApexShouldFail() throws Exception { - pushTestApex(); + pushTestApex(APK_IN_APEX_TESTAPEX_NAME + "_v1.apex"); runPhase("testDuplicateApkInApexShouldFail_Commit"); getDevice().reboot(); runPhase("testDuplicateApkInApexShouldFail_Verify"); @@ -344,6 +345,12 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test { runPhase("testApexActivationFailureIsCapturedInSession_Verify"); } + @Test + public void testRebootlessUpdates() throws Exception { + pushTestApex("test.rebootless_apex_v1.apex"); + runPhase("testRebootlessUpdates"); + } + private List<String> getStagingDirectories() throws DeviceNotAvailableException { String baseDir = "/data/app-staging"; try { |