Merge "Cleanup IME subtype switching controller and tests" into main
diff --git a/apct-tests/perftests/core/src/android/permission/AppOpsPerfTest.kt b/apct-tests/perftests/core/src/android/permission/AppOpsPerfTest.kt
deleted file mode 100644
index daf991c..0000000
--- a/apct-tests/perftests/core/src/android/permission/AppOpsPerfTest.kt
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.permission
-
-import android.app.AppOpsManager
-import android.content.Context
-import android.perftests.utils.PerfStatusReporter
-import androidx.test.core.app.ApplicationProvider
-import androidx.test.filters.LargeTest
-import org.junit.Before
-import org.junit.Rule
-import org.junit.Test
-
-@LargeTest
-/**
- * Performance unit tests for app ops APIs.
- *
- * The APIs under test are used for checking permissions and tracking permission accesses and are
- * therefore invoked frequently by the system for all permission-protected data accesses, hence
- * these APIs should be monitored closely for performance.
- */
-class AppOpsPerfTest {
- @get:Rule val perfStatusReporter = PerfStatusReporter()
- private lateinit var appOpsManager: AppOpsManager
- private lateinit var opPackageName: String
- private var opPackageUid: Int = 0
-
- @Before
- fun setUp() {
- val context: Context = ApplicationProvider.getApplicationContext()
- appOpsManager = context.getSystemService<AppOpsManager>(AppOpsManager::class.java)!!
- opPackageName = context.getOpPackageName()
- opPackageUid = context.getPackageManager().getPackageUid(opPackageName, 0)
- }
-
- @Test
- fun testNoteOp() {
- val state = perfStatusReporter.benchmarkState
- while (state.keepRunning()) {
- appOpsManager.noteOp(
- AppOpsManager.OPSTR_FINE_LOCATION,
- opPackageUid,
- opPackageName,
- null,
- null
- )
- }
- }
-
- @Test
- fun testUnsafeCheckOp() {
- val state = perfStatusReporter.benchmarkState
- while (state.keepRunning()) {
- appOpsManager.unsafeCheckOp(
- AppOpsManager.OPSTR_FINE_LOCATION,
- opPackageUid,
- opPackageName
- )
- }
- }
-}
diff --git a/apct-tests/perftests/core/src/android/permission/OWNERS b/apct-tests/perftests/core/src/android/permission/OWNERS
deleted file mode 100644
index b4b2b9e..0000000
--- a/apct-tests/perftests/core/src/android/permission/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# Bug component: 137825
-
-include platform/frameworks/base:/core/java/android/permission/OWNERS
\ No newline at end of file
diff --git a/api/StubLibraries.bp b/api/StubLibraries.bp
index 6cfd2e0..5b7e25b 100644
--- a/api/StubLibraries.bp
+++ b/api/StubLibraries.bp
@@ -922,6 +922,7 @@
"i18n.module.public.api.stubs.source.system.api.contribution",
"i18n.module.public.api.stubs.source.module_lib.api.contribution",
],
+ previous_api: ":android.api.public.latest",
}
// Java API library definitions per API surface
diff --git a/core/api/current.txt b/core/api/current.txt
index 831cf01..5eeb299 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -55309,7 +55309,7 @@
field public static final int TYPE_MAGNIFICATION_OVERLAY = 6; // 0x6
field public static final int TYPE_SPLIT_SCREEN_DIVIDER = 5; // 0x5
field public static final int TYPE_SYSTEM = 3; // 0x3
- field @FlaggedApi("android.view.accessibility.add_type_window_control") public static final int TYPE_WINDOW_CONTROL = 7; // 0x7
+ field @FlaggedApi("android.view.accessibility.enable_type_window_control") public static final int TYPE_WINDOW_CONTROL = 7; // 0x7
}
public class CaptioningManager {
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index c8e1e4d..0947e33 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -3701,7 +3701,7 @@
* @see View#findViewById(int)
* @see Activity#requireViewById(int)
*/
- @Nullable
+ /* TODO(b/347672184): Re-add @Nullable */
public <T extends View> T findViewById(@IdRes int id) {
return getWindow().findViewById(id);
}
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index cd7f1e4..57d9a71 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -565,7 +565,7 @@
* @see View#findViewById(int)
* @see Dialog#requireViewById(int)
*/
- @Nullable
+ /* TODO(b/347672184): Re-add @Nullable */
public <T extends View> T findViewById(@IdRes int id) {
return mWindow.findViewById(id);
}
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index a1fa404..a1c4267 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -6222,6 +6222,7 @@
if (appIconRes != 0) {
mN.mAppIcon = Icon.createWithResource(mContext, appIconRes);
contentView.setImageViewIcon(R.id.icon, mN.mAppIcon);
+ contentView.setBoolean(R.id.icon, "setShouldShowAppIcon", true);
usingAppIcon = true;
} else {
Log.w(TAG, "bindSmallIcon: could not get the app icon");
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index 370aff8..bb7f893 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -1745,10 +1745,15 @@
if (r.getImpl() != null) {
final ResourcesImpl oldImpl = r.getImpl();
// ResourcesImpl constructor will help to append shared library asset paths.
- final ResourcesImpl newImpl = new ResourcesImpl(oldImpl.getAssets(),
- oldImpl.getMetrics(), oldImpl.getConfiguration(),
- oldImpl.getDisplayAdjustments());
- r.setImpl(newImpl);
+ if (oldImpl.getAssets().isUpToDate()) {
+ final ResourcesImpl newImpl = new ResourcesImpl(oldImpl.getAssets(),
+ oldImpl.getMetrics(), oldImpl.getConfiguration(),
+ oldImpl.getDisplayAdjustments());
+ r.setImpl(newImpl);
+ } else {
+ Slog.w(TAG, "Skip appending shared library asset paths for the "
+ + "Resource as its assets are not up to date.");
+ }
}
}
}
diff --git a/core/java/android/app/admin/flags/flags.aconfig b/core/java/android/app/admin/flags/flags.aconfig
index 7d5806a..8227112 100644
--- a/core/java/android/app/admin/flags/flags.aconfig
+++ b/core/java/android/app/admin/flags/flags.aconfig
@@ -383,3 +383,13 @@
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "management_mode_policy_metrics"
+ namespace: "enterprise"
+ description: "Enabling management mode and password complexity policy metrics collection"
+ bug: "293091314"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index dfa29738..a6edab1 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -7630,6 +7630,13 @@
| FLAG_GRANT_PREFIX_URI_PERMISSION;
/**
+ * Flags that are not normally set by application code, but set for you by the system.
+ */
+ private static final int SYSTEM_ONLY_FLAGS = FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
+ | FLAG_ACTIVITY_BROUGHT_TO_FRONT
+ | FLAG_RECEIVER_FROM_SHELL;
+
+ /**
* Local flag indicating this instance was created by copy constructor.
*/
private static final int LOCAL_FLAG_FROM_COPY = 1 << 0;
@@ -7682,6 +7689,11 @@
@TestApi
public static final int EXTENDED_FLAG_FILTER_MISMATCH = 1 << 0;
+ /**
+ * Extended flags that are not normally set by application code, but set for you by the system.
+ */
+ private static final int SYSTEM_ONLY_EXTENDED_FLAGS = EXTENDED_FLAG_FILTER_MISMATCH;
+
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// toUri() and parseUri() options.
@@ -12625,6 +12637,28 @@
}
}
+ /**
+ * Prepare this {@link Intent} to enter system_server.
+ *
+ * @hide
+ */
+ public void prepareToEnterSystemServer() {
+ // Refuse possible leaked file descriptors
+ if (hasFileDescriptors()) {
+ throw new IllegalArgumentException("File descriptors passed in Intent");
+ }
+ // These flags are set only by the system, and should be stripped out as soon as the intent
+ // is received by system_server from the caller so it can be properly updated later.
+ removeFlags(SYSTEM_ONLY_FLAGS);
+ removeExtendedFlags(SYSTEM_ONLY_EXTENDED_FLAGS);
+ if (mOriginalIntent != null) {
+ mOriginalIntent.prepareToEnterSystemServer();
+ }
+ if (mSelector != null) {
+ mSelector.prepareToEnterSystemServer();
+ }
+ }
+
/** @hide */
public boolean hasWebURI() {
if (getData() == null) {
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index 273e40a..c0c1c31 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -32,6 +32,7 @@
import android.content.res.loader.ResourcesLoader;
import android.os.Build;
import android.os.ParcelFileDescriptor;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
import android.util.SparseArray;
@@ -448,7 +449,7 @@
@Deprecated
@UnsupportedAppUsage
public int addAssetPath(String path) {
- return addAssetPathInternal(path, false /*overlay*/, false /*appAsLib*/);
+ return addAssetPathInternal(List.of(path), false, false, false);
}
/**
@@ -458,7 +459,7 @@
@Deprecated
@UnsupportedAppUsage
public int addAssetPathAsSharedLibrary(String path) {
- return addAssetPathInternal(path, false /*overlay*/, true /*appAsLib*/);
+ return addAssetPathInternal(List.of(path), false, true, false);
}
/**
@@ -468,35 +469,103 @@
@Deprecated
@UnsupportedAppUsage
public int addOverlayPath(String path) {
- return addAssetPathInternal(path, true /*overlay*/, false /*appAsLib*/);
+ return addAssetPathInternal(List.of(path), true, false, false);
}
/**
* @hide
*/
- public void addSharedLibraryPaths(@NonNull String[] paths) {
- final int length = paths.length;
- for (int i = 0; i < length; i++) {
- addAssetPathInternal(paths[i], false, true);
+ public void addSharedLibraryPaths(@NonNull List<String> paths) {
+ addAssetPathInternal(paths, false, true, true);
+ }
+
+ private int addAssetPathInternal(List<String> paths, boolean overlay, boolean appAsLib,
+ boolean presetAssets) {
+ Objects.requireNonNull(paths, "paths");
+ if (paths.isEmpty()) {
+ return 0;
+ }
+
+ synchronized (this) {
+ ensureOpenLocked();
+
+ // See if we already have some of the paths loaded.
+ final int originalAssetsCount = mApkAssets.length;
+
+ // Getting an assets' path is a relatively expensive operation, cache them.
+ final ArrayMap<String, Integer> assetPaths = new ArrayMap<>(originalAssetsCount);
+ for (int i = 0; i < originalAssetsCount; i++) {
+ assetPaths.put(mApkAssets[i].getAssetPath(), i);
+ }
+
+ final ArrayList<String> newPaths = new ArrayList<>(paths.size());
+ int lastFoundIndex = -1;
+ for (int i = 0, pathsSize = paths.size(); i < pathsSize; i++) {
+ final var path = paths.get(i);
+ final int index = assetPaths.getOrDefault(path, -1);
+ if (index < 0) {
+ newPaths.add(path);
+ } else {
+ lastFoundIndex = index;
+ }
+ }
+ if (newPaths.isEmpty()) {
+ return lastFoundIndex + 1;
+ }
+
+ final var newAssets = loadAssets(newPaths, overlay, appAsLib);
+ if (newAssets.isEmpty()) {
+ return 0;
+ }
+ mApkAssets = makeNewAssetsArrayLocked(newAssets);
+ nativeSetApkAssets(mObject, mApkAssets, true, presetAssets);
+ invalidateCachesLocked(-1);
+ return originalAssetsCount + 1;
}
}
- private int addAssetPathInternal(String path, boolean overlay, boolean appAsLib) {
- Objects.requireNonNull(path, "path");
- synchronized (this) {
- ensureOpenLocked();
- final int count = mApkAssets.length;
-
- // See if we already have it loaded.
- for (int i = 0; i < count; i++) {
- if (mApkAssets[i].getAssetPath().equals(path)) {
- return i + 1;
- }
+ /**
+ * Insert the new assets preserving the correct order: all non-loader assets go before all
+ * of the loader assets.
+ */
+ @GuardedBy("this")
+ private @NonNull ApkAssets[] makeNewAssetsArrayLocked(
+ @NonNull ArrayList<ApkAssets> newNonLoaderAssets) {
+ final int originalAssetsCount = mApkAssets.length;
+ int firstLoaderIndex = originalAssetsCount;
+ for (int i = 0; i < originalAssetsCount; i++) {
+ if (mApkAssets[i].isForLoader()) {
+ firstLoaderIndex = i;
+ break;
}
+ }
+ final int newAssetsSize = newNonLoaderAssets.size();
+ final var newAssetsArray = new ApkAssets[originalAssetsCount + newAssetsSize];
+ if (firstLoaderIndex > 0) {
+ // This should always be true, but who knows...
+ System.arraycopy(mApkAssets, 0, newAssetsArray, 0, firstLoaderIndex);
+ }
+ for (int i = 0; i < newAssetsSize; i++) {
+ newAssetsArray[firstLoaderIndex + i] = newNonLoaderAssets.get(i);
+ }
+ if (originalAssetsCount > firstLoaderIndex) {
+ System.arraycopy(
+ mApkAssets, firstLoaderIndex,
+ newAssetsArray, firstLoaderIndex + newAssetsSize,
+ originalAssetsCount - firstLoaderIndex);
+ }
+ return newAssetsArray;
+ }
- final ApkAssets assets;
+ private static @NonNull ArrayList<ApkAssets> loadAssets(@NonNull ArrayList<String> paths,
+ boolean overlay, boolean appAsLib) {
+ final int pathsSize = paths.size();
+ final var loadedAssets = new ArrayList<ApkAssets>(pathsSize);
+ for (int i = 0; i < pathsSize; i++) {
+ final var path = paths.get(i);
try {
- if (overlay) {
+ final ApkAssets assets;
+ if (overlay || path.endsWith(".frro")) {
// TODO(b/70343104): This hardcoded path will be removed once
// addAssetPathInternal is deleted.
final String idmapPath = "/data/resource-cache/"
@@ -507,16 +576,12 @@
assets = ApkAssets.loadFromPath(path,
appAsLib ? ApkAssets.PROPERTY_DYNAMIC : 0);
}
+ loadedAssets.add(assets);
} catch (IOException e) {
- return 0;
+ Log.w(TAG, "Failed to load asset, path = " + path, e);
}
-
- mApkAssets = Arrays.copyOf(mApkAssets, count + 1);
- mApkAssets[count] = assets;
- nativeSetApkAssets(mObject, mApkAssets, true, false);
- invalidateCachesLocked(-1);
- return count + 1;
}
+ return loadedAssets;
}
/** @hide */
diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java
index 31cacb7..9f8b974 100644
--- a/core/java/android/content/res/ResourcesImpl.java
+++ b/core/java/android/content/res/ResourcesImpl.java
@@ -49,6 +49,7 @@
import android.os.ParcelFileDescriptor;
import android.os.Trace;
import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
@@ -71,6 +72,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Locale;
@@ -205,13 +207,21 @@
@Nullable Configuration config, @NonNull DisplayAdjustments displayAdjustments) {
mAssets = assets;
if (Flags.registerResourcePaths()) {
- ArrayMap<String, SharedLibraryAssets> sharedLibMap =
+ final ArraySet<String> uniquePaths = new ArraySet<>();
+ final ArrayList<String> orderedPaths = new ArrayList<>();
+ final ArrayMap<String, SharedLibraryAssets> sharedLibMap =
ResourcesManager.getInstance().getSharedLibAssetsMap();
final int size = sharedLibMap.size();
for (int i = 0; i < size; i++) {
- assets.addSharedLibraryPaths(sharedLibMap.valueAt(i).getAllAssetPaths());
+ final var paths = sharedLibMap.valueAt(i).getAllAssetPaths();
+ for (int j = 0; j < paths.length; j++) {
+ if (uniquePaths.add(paths[j])) {
+ orderedPaths.add(paths[j]);
+ }
+ }
}
- mSharedLibCount = sharedLibMap.size();
+ assets.addSharedLibraryPaths(orderedPaths);
+ mSharedLibCount = size;
}
mMetrics.setToDefaults();
mDisplayAdjustments = displayAdjustments;
diff --git a/core/java/android/os/BatteryConsumer.java b/core/java/android/os/BatteryConsumer.java
index 02f3a25..744f6a8 100644
--- a/core/java/android/os/BatteryConsumer.java
+++ b/core/java/android/os/BatteryConsumer.java
@@ -888,6 +888,13 @@
return (T) this;
}
+ @SuppressWarnings("unchecked")
+ @NonNull
+ public T addConsumedPowerForCustomComponent(int componentId, double componentPower) {
+ mPowerComponentsBuilder.addConsumedPowerForCustomComponent(componentId, componentPower);
+ return (T) this;
+ }
+
/**
* Sets the amount of time used by the specified component, e.g. CPU, WiFi etc.
*
diff --git a/core/java/android/os/PowerComponents.java b/core/java/android/os/PowerComponents.java
index 164e265..b035f12 100644
--- a/core/java/android/os/PowerComponents.java
+++ b/core/java/android/os/PowerComponents.java
@@ -516,6 +516,19 @@
}
@NonNull
+ public Builder addConsumedPowerForCustomComponent(int componentId, double componentPower) {
+ final int index = componentId - BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID;
+ if (index < 0 || index >= mData.layout.customPowerComponentCount) {
+ throw new IllegalArgumentException(
+ "Unsupported custom power component ID: " + componentId);
+ }
+ mData.putDouble(mData.layout.firstCustomConsumedPowerColumn + index,
+ mData.getDouble(mData.layout.firstCustomConsumedPowerColumn + index)
+ + componentPower);
+ return this;
+ }
+
+ @NonNull
public Builder setUsageDurationMillis(BatteryConsumer.Key key,
long componentUsageDurationMillis) {
mData.putLong(key.mDurationColumnIndex, componentUsageDurationMillis);
diff --git a/core/java/android/os/SharedMemory.java b/core/java/android/os/SharedMemory.java
index cba4423..d008034 100644
--- a/core/java/android/os/SharedMemory.java
+++ b/core/java/android/os/SharedMemory.java
@@ -25,6 +25,8 @@
import dalvik.system.VMRuntime;
+import libcore.io.IoUtils;
+
import java.io.Closeable;
import java.io.FileDescriptor;
import java.io.IOException;
@@ -63,7 +65,7 @@
mMemoryRegistration = new MemoryRegistration(mSize);
mCleaner = Cleaner.create(mFileDescriptor,
- new Closer(mFileDescriptor.getInt$(), mMemoryRegistration));
+ new Closer(mFileDescriptor, mMemoryRegistration));
}
/**
@@ -326,21 +328,20 @@
* Cleaner that closes the FD
*/
private static final class Closer implements Runnable {
- private int mFd;
+ private FileDescriptor mFd;
private MemoryRegistration mMemoryReference;
- private Closer(int fd, MemoryRegistration memoryReference) {
+ private Closer(FileDescriptor fd, MemoryRegistration memoryReference) {
mFd = fd;
+ IoUtils.setFdOwner(mFd, this);
mMemoryReference = memoryReference;
}
@Override
public void run() {
- try {
- FileDescriptor fd = new FileDescriptor();
- fd.setInt$(mFd);
- Os.close(fd);
- } catch (ErrnoException e) { /* swallow error */ }
+ IoUtils.closeQuietly(mFd);
+ mFd = null;
+
mMemoryReference.release();
mMemoryReference = null;
}
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 3f9c819..a769643 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -738,7 +738,7 @@
* @see View#findViewById(int)
* @see DreamService#requireViewById(int)
*/
- @Nullable
+ /* TODO(b/347672184): Re-add @Nullable */
public <T extends View> T findViewById(@IdRes int id) {
return getWindow().findViewById(id);
}
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index e20b15e..396be7b 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -422,7 +422,7 @@
/**
* Free all server-side state associated with this surface and
* release this object's reference. This method can only be
- * called from the process that created the service.
+ * called from the process that created the surface.
* @hide
*/
@UnsupportedAppUsage
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 9bc1511..3df72e8 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -27534,7 +27534,7 @@
* @return a view with given ID if found, or {@code null} otherwise
* @see View#requireViewById(int)
*/
- @Nullable
+ /* TODO(b/347672184): Re-add @Nullable */
public final <T extends View> T findViewById(@IdRes int id) {
if (id == NO_ID) {
return null;
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 2377b86..9f4d7e2 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -126,6 +126,7 @@
import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
import static com.android.window.flags.Flags.activityWindowInfoFlag;
import static com.android.window.flags.Flags.enableBufferTransformHintFromDisplay;
+import static com.android.window.flags.Flags.insetsControlChangedItem;
import static com.android.window.flags.Flags.setScPropertiesInClient;
import static com.android.window.flags.Flags.windowSessionRelayoutInfo;
import static com.android.text.flags.Flags.disableHandwritingInitiatorForIme;
@@ -7511,6 +7512,8 @@
final KeyEvent event = (KeyEvent)q.mEvent;
if (mView.dispatchKeyEventPreIme(event)) {
return FINISH_HANDLED;
+ } else if (q.forPreImeOnly()) {
+ return FINISH_NOT_HANDLED;
}
return FORWARD;
}
@@ -10007,6 +10010,7 @@
public static final int FLAG_RESYNTHESIZED = 1 << 4;
public static final int FLAG_UNHANDLED = 1 << 5;
public static final int FLAG_MODIFIED_FOR_COMPATIBILITY = 1 << 6;
+ public static final int FLAG_PRE_IME_ONLY = 1 << 7;
public QueuedInputEvent mNext;
@@ -10014,6 +10018,13 @@
public InputEventReceiver mReceiver;
public int mFlags;
+ public boolean forPreImeOnly() {
+ if ((mFlags & FLAG_PRE_IME_ONLY) != 0) {
+ return true;
+ }
+ return false;
+ }
+
public boolean shouldSkipIme() {
if ((mFlags & FLAG_DELIVER_POST_IME) != 0) {
return true;
@@ -10040,6 +10051,7 @@
hasPrevious = flagToString("FINISHED_HANDLED", FLAG_FINISHED_HANDLED, hasPrevious, sb);
hasPrevious = flagToString("RESYNTHESIZED", FLAG_RESYNTHESIZED, hasPrevious, sb);
hasPrevious = flagToString("UNHANDLED", FLAG_UNHANDLED, hasPrevious, sb);
+ hasPrevious = flagToString("FLAG_PRE_IME_ONLY", FLAG_PRE_IME_ONLY, hasPrevious, sb);
if (!hasPrevious) {
sb.append("0");
}
@@ -10096,7 +10108,7 @@
}
@UnsupportedAppUsage
- void enqueueInputEvent(InputEvent event,
+ QueuedInputEvent enqueueInputEvent(InputEvent event,
InputEventReceiver receiver, int flags, boolean processImmediately) {
QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);
@@ -10135,6 +10147,7 @@
} else {
scheduleProcessInputEvents();
}
+ return q;
}
private void scheduleProcessInputEvents() {
@@ -11417,8 +11430,13 @@
@Override
public void insetsControlChanged(InsetsState insetsState,
InsetsSourceControl.Array activeControls) {
- final boolean isFromInsetsControlChangeItem = mIsFromTransactionItem;
- mIsFromTransactionItem = false;
+ final boolean isFromInsetsControlChangeItem;
+ if (insetsControlChangedItem()) {
+ isFromInsetsControlChangeItem = mIsFromTransactionItem;
+ mIsFromTransactionItem = false;
+ } else {
+ isFromInsetsControlChangeItem = false;
+ }
final ViewRootImpl viewAncestor = mViewAncestor.get();
if (viewAncestor == null) {
if (isFromInsetsControlChangeItem) {
@@ -12456,29 +12474,45 @@
+ "IWindow:%s Session:%s",
mOnBackInvokedDispatcher, mBasePackageName, mWindow, mWindowSession));
}
- mOnBackInvokedDispatcher.attachToWindow(mWindowSession, mWindow,
+ mOnBackInvokedDispatcher.attachToWindow(mWindowSession, mWindow, this,
mImeBackAnimationController);
}
- private void sendBackKeyEvent(int action) {
+ /**
+ * Sends {@link KeyEvent#ACTION_DOWN ACTION_DOWN} and {@link KeyEvent#ACTION_UP ACTION_UP}
+ * back key events
+ *
+ * @param preImeOnly whether the back events should be sent to the pre-ime stage only
+ * @return whether the event was handled (i.e. onKeyPreIme consumed it if preImeOnly=true)
+ */
+ public boolean injectBackKeyEvents(boolean preImeOnly) {
+ boolean consumed;
+ try {
+ processingBackKey(true);
+ sendBackKeyEvent(KeyEvent.ACTION_DOWN, preImeOnly);
+ consumed = sendBackKeyEvent(KeyEvent.ACTION_UP, preImeOnly);
+ } finally {
+ processingBackKey(false);
+ }
+ return consumed;
+ }
+
+ private boolean sendBackKeyEvent(int action, boolean preImeOnly) {
long when = SystemClock.uptimeMillis();
final KeyEvent ev = new KeyEvent(when, when, action,
KeyEvent.KEYCODE_BACK, 0 /* repeat */, 0 /* metaState */,
KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /* scancode */,
KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY,
InputDevice.SOURCE_KEYBOARD);
- enqueueInputEvent(ev, null /* receiver */, 0 /* flags */, true /* processImmediately */);
+ int flags = preImeOnly ? QueuedInputEvent.FLAG_PRE_IME_ONLY : 0;
+ QueuedInputEvent q = enqueueInputEvent(ev, null /* receiver */, flags,
+ true /* processImmediately */);
+ return (q.mFlags & QueuedInputEvent.FLAG_FINISHED_HANDLED) != 0;
}
private void registerCompatOnBackInvokedCallback() {
mCompatOnBackInvokedCallback = () -> {
- try {
- processingBackKey(true);
- sendBackKeyEvent(KeyEvent.ACTION_DOWN);
- sendBackKeyEvent(KeyEvent.ACTION_UP);
- } finally {
- processingBackKey(false);
- }
+ injectBackKeyEvents(/* preImeOnly */ false);
};
if (mOnBackInvokedDispatcher.hasImeOnBackInvokedDispatcher()) {
Log.d(TAG, "Skip registering CompatOnBackInvokedCallback on IME dispatcher");
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 52000d9..7cb70bd 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -1722,7 +1722,7 @@
* @see View#findViewById(int)
* @see Window#requireViewById(int)
*/
- @Nullable
+ /* TODO(b/347672184): Re-add @Nullable */
public <T extends View> T findViewById(@IdRes int id) {
return getDecorView().findViewById(id);
}
diff --git a/core/java/android/view/accessibility/AccessibilityWindowInfo.java b/core/java/android/view/accessibility/AccessibilityWindowInfo.java
index 749f977..c92593f 100644
--- a/core/java/android/view/accessibility/AccessibilityWindowInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityWindowInfo.java
@@ -97,7 +97,7 @@
/**
* Window type: A system window that has the function to control an associated window.
*/
- @FlaggedApi(Flags.FLAG_ADD_TYPE_WINDOW_CONTROL)
+ @FlaggedApi(Flags.FLAG_ENABLE_TYPE_WINDOW_CONTROL)
public static final int TYPE_WINDOW_CONTROL = 7;
/* Special values for window IDs */
@@ -880,7 +880,7 @@
* @hide
*/
public static String typeToString(int type) {
- if (Flags.addTypeWindowControl() && type == TYPE_WINDOW_CONTROL) {
+ if (Flags.enableTypeWindowControl() && type == TYPE_WINDOW_CONTROL) {
return "TYPE_WINDOW_CONTROL";
}
diff --git a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
index ab7b226..95d001f 100644
--- a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
+++ b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
@@ -122,9 +122,8 @@
flag {
namespace: "accessibility"
- name: "add_type_window_control"
+ name: "enable_type_window_control"
is_exported: true
- is_fixed_read_only: true
description: "adds new TYPE_WINDOW_CONTROL to AccessibilityWindowInfo for detecting Window Decorations"
bug: "320445550"
}
diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java
index d74867c..724e8fa 100644
--- a/core/java/android/view/contentcapture/ContentCaptureManager.java
+++ b/core/java/android/view/contentcapture/ContentCaptureManager.java
@@ -18,7 +18,6 @@
import static android.view.contentcapture.ContentCaptureHelper.sDebug;
import static android.view.contentcapture.ContentCaptureHelper.sVerbose;
import static android.view.contentcapture.ContentCaptureHelper.toSet;
-import static android.view.contentcapture.flags.Flags.runOnBackgroundThreadEnabled;
import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
@@ -602,26 +601,16 @@
public ContentCaptureSession getMainContentCaptureSession() {
synchronized (mLock) {
if (mMainSession == null) {
- mMainSession = prepareMainSession();
- if (sVerbose) Log.v(TAG, "getMainContentCaptureSession(): created " + mMainSession);
- }
- return mMainSession;
- }
- }
-
- @NonNull
- @GuardedBy("mLock")
- private ContentCaptureSession prepareMainSession() {
- if (runOnBackgroundThreadEnabled()) {
- return new MainContentCaptureSessionV2(
+ mMainSession = new MainContentCaptureSession(
mContext,
this,
prepareUiHandler(),
prepareContentCaptureHandler(),
mService
- );
- } else {
- return new MainContentCaptureSession(mContext, this, prepareUiHandler(), mService);
+ );
+ if (sVerbose) Log.v(TAG, "getMainContentCaptureSession(): created " + mMainSession);
+ }
+ return mMainSession;
}
}
diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java
index a90c94e..eb827dd 100644
--- a/core/java/android/view/contentcapture/MainContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java
@@ -69,16 +69,13 @@
import java.util.Collections;
import java.util.List;
import java.util.NoSuchElementException;
+import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
-// TODO(b/309411951): Replace V2 as the only main session once the experiment is done.
/**
* Main session associated with a context.
*
- * <p>This session is created when the activity starts and finished when it stops; clients can use
- * it to create children activities.
- *
* @hide
*/
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
@@ -107,7 +104,10 @@
private final ContentCaptureManager mManager;
@NonNull
- private final Handler mHandler;
+ private final Handler mUiHandler;
+
+ @NonNull
+ private final Handler mContentCaptureHandler;
/**
* Interface to the system_server binder object - it's only used to start the session (and
@@ -142,6 +142,18 @@
public ComponentName mComponentName;
/**
+ * Thread-safe queue of events held to be processed as a batch.
+ *
+ * Because it is not guaranteed that the events will be enqueued from a single thread, the
+ * implementation must be thread-safe to prevent unexpected behaviour.
+ *
+ * @hide
+ */
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+ @NonNull
+ public final ConcurrentLinkedQueue<ContentCaptureEvent> mEventProcessQueue;
+
+ /**
* List of events held to be sent to the {@link ContentCaptureService} as a batch.
*
* @hide
@@ -200,14 +212,14 @@
binder = resultData.getBinder(EXTRA_BINDER);
if (binder == null) {
Log.wtf(TAG, "No " + EXTRA_BINDER + " extra result");
- mainSession.mHandler.post(() -> mainSession.resetSession(
+ mainSession.runOnContentCaptureThread(() -> mainSession.resetSession(
STATE_DISABLED | STATE_INTERNAL_ERROR));
return;
}
} else {
binder = null;
}
- mainSession.mHandler.post(() ->
+ mainSession.runOnContentCaptureThread(() ->
mainSession.onSessionStarted(resultCode, binder));
}
}
@@ -217,17 +229,21 @@
public MainContentCaptureSession(
@NonNull ContentCaptureManager.StrippedContext context,
@NonNull ContentCaptureManager manager,
- @NonNull Handler handler,
+ @NonNull Handler uiHandler,
+ @NonNull Handler contentCaptureHandler,
@NonNull IContentCaptureManager systemServerInterface) {
mContext = context;
mManager = manager;
- mHandler = handler;
+ mUiHandler = uiHandler;
+ mContentCaptureHandler = contentCaptureHandler;
mSystemServerInterface = systemServerInterface;
final int logHistorySize = mManager.mOptions.logHistorySize;
mFlushHistory = logHistorySize > 0 ? new LocalLog(logHistorySize) : null;
mSessionStateReceiver = new SessionStateReceiver(this);
+
+ mEventProcessQueue = new ConcurrentLinkedQueue<>();
}
@Override
@@ -248,7 +264,13 @@
@Override
void start(@NonNull IBinder token, @NonNull IBinder shareableActivityToken,
@NonNull ComponentName component, int flags) {
- checkOnUiThread();
+ runOnContentCaptureThread(
+ () -> startImpl(token, shareableActivityToken, component, flags));
+ }
+
+ private void startImpl(@NonNull IBinder token, @NonNull IBinder shareableActivityToken,
+ @NonNull ComponentName component, int flags) {
+ checkOnContentCaptureThread();
if (!isContentCaptureEnabled()) return;
if (sVerbose) {
@@ -282,17 +304,15 @@
Log.w(TAG, "Error starting session for " + component.flattenToShortString() + ": " + e);
}
}
-
@Override
void onDestroy() {
- mHandler.removeMessages(MSG_FLUSH);
- mHandler.post(() -> {
+ clearAndRunOnContentCaptureThread(() -> {
try {
flush(FLUSH_REASON_SESSION_FINISHED);
} finally {
destroySession();
}
- });
+ }, MSG_FLUSH);
}
/**
@@ -305,7 +325,7 @@
*/
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
public void onSessionStarted(int resultCode, @Nullable IBinder binder) {
- checkOnUiThread();
+ checkOnContentCaptureThread();
if (binder != null) {
mDirectServiceInterface = IContentCaptureDirectManager.Stub.asInterface(binder);
mDirectServiceVulture = () -> {
@@ -324,7 +344,7 @@
mContentProtectionEventProcessor =
new ContentProtectionEventProcessor(
mManager.getContentProtectionEventBuffer(),
- mHandler,
+ mContentCaptureHandler,
mSystemServerInterface,
mComponentName.getPackageName(),
mManager.mOptions.contentProtectionOptions);
@@ -354,7 +374,7 @@
}
private void sendEvent(@NonNull ContentCaptureEvent event, boolean forceFlush) {
- checkOnUiThread();
+ checkOnContentCaptureThread();
final int eventType = event.getType();
if (sVerbose) Log.v(TAG, "handleSendEvent(" + getDebugState() + "): " + event);
if (!hasStarted() && eventType != ContentCaptureEvent.TYPE_SESSION_STARTED
@@ -398,14 +418,14 @@
}
private void sendContentProtectionEvent(@NonNull ContentCaptureEvent event) {
- checkOnUiThread();
+ checkOnContentCaptureThread();
if (mContentProtectionEventProcessor != null) {
mContentProtectionEventProcessor.processEvent(event);
}
}
private void sendContentCaptureEvent(@NonNull ContentCaptureEvent event, boolean forceFlush) {
- checkOnUiThread();
+ checkOnContentCaptureThread();
final int eventType = event.getType();
final int maxBufferSize = mManager.mOptions.maxBufferSize;
if (mEvents == null) {
@@ -540,12 +560,12 @@
}
private boolean hasStarted() {
- checkOnUiThread();
+ checkOnContentCaptureThread();
return mState != UNKNOWN_STATE;
}
private void scheduleFlush(@FlushReason int reason, boolean checkExisting) {
- checkOnUiThread();
+ checkOnContentCaptureThread();
if (sVerbose) {
Log.v(TAG, "handleScheduleFlush(" + getDebugState(reason)
+ ", checkExisting=" + checkExisting);
@@ -562,9 +582,9 @@
+ "when disabled. events=" + (mEvents == null ? null : mEvents.size()));
return;
}
- if (checkExisting && mHandler.hasMessages(MSG_FLUSH)) {
+ if (checkExisting && mContentCaptureHandler.hasMessages(MSG_FLUSH)) {
// "Renew" the flush message by removing the previous one
- mHandler.removeMessages(MSG_FLUSH);
+ mContentCaptureHandler.removeMessages(MSG_FLUSH);
}
final int flushFrequencyMs;
@@ -586,12 +606,12 @@
+ flushFrequencyMs + "ms: " + TimeUtils.logTimeOfDay(mNextFlush));
}
// Post using a Runnable directly to trim a few μs from PooledLambda.obtainMessage()
- mHandler.postDelayed(() ->
+ mContentCaptureHandler.postDelayed(() ->
flushIfNeeded(reason), MSG_FLUSH, flushFrequencyMs);
}
private void flushIfNeeded(@FlushReason int reason) {
- checkOnUiThread();
+ checkOnContentCaptureThread();
if (mEvents == null || mEvents.isEmpty()) {
if (sVerbose) Log.v(TAG, "Nothing to flush");
return;
@@ -603,7 +623,11 @@
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
@Override
public void flush(@FlushReason int reason) {
- checkOnUiThread();
+ runOnContentCaptureThread(() -> flushImpl(reason));
+ }
+
+ private void flushImpl(@FlushReason int reason) {
+ checkOnContentCaptureThread();
if (mEvents == null || mEvents.size() == 0) {
if (sVerbose) {
Log.v(TAG, "Don't flush for empty event buffer.");
@@ -626,7 +650,7 @@
Log.v(TAG, "handleForceFlush(" + getDebugState(reason) + "): hold your horses, "
+ "client not ready: " + mEvents);
}
- if (!mHandler.hasMessages(MSG_FLUSH)) {
+ if (!mContentCaptureHandler.hasMessages(MSG_FLUSH)) {
scheduleFlush(reason, /* checkExisting= */ false);
}
return;
@@ -652,7 +676,7 @@
mFlushHistory.log(logRecord);
}
try {
- mHandler.removeMessages(MSG_FLUSH);
+ mContentCaptureHandler.removeMessages(MSG_FLUSH);
final ParceledListSlice<ContentCaptureEvent> events = clearEvents();
mDirectServiceInterface.sendEvents(events, reason, mManager.mOptions);
@@ -672,7 +696,7 @@
*/
@NonNull
private ParceledListSlice<ContentCaptureEvent> clearEvents() {
- checkOnUiThread();
+ checkOnContentCaptureThread();
// NOTE: we must save a reference to the current mEvents and then set it to to null,
// otherwise clearing it would clear it in the receiving side if the service is also local.
if (mEvents == null) {
@@ -687,7 +711,7 @@
/** hide */
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
public void destroySession() {
- checkOnUiThread();
+ checkOnContentCaptureThread();
if (sDebug) {
Log.d(TAG, "Destroying session (ctx=" + mContext + ", id=" + mId + ") with "
+ (mEvents == null ? 0 : mEvents.size()) + " event(s) for "
@@ -707,6 +731,7 @@
}
mDirectServiceInterface = null;
mContentProtectionEventProcessor = null;
+ mEventProcessQueue.clear();
}
// TODO(b/122454205): once we support multiple sessions, we might need to move some of these
@@ -714,7 +739,7 @@
/** @hide */
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
public void resetSession(int newState) {
- checkOnUiThread();
+ checkOnContentCaptureThread();
if (sVerbose) {
Log.v(TAG, "handleResetSession(" + getActivityName() + "): from "
+ getStateAsString(mState) + " to " + getStateAsString(newState));
@@ -735,21 +760,21 @@
}
mDirectServiceInterface = null;
mContentProtectionEventProcessor = null;
- mHandler.removeMessages(MSG_FLUSH);
+ mContentCaptureHandler.removeMessages(MSG_FLUSH);
}
@Override
void internalNotifyViewAppeared(int sessionId, @NonNull ViewStructureImpl node) {
final ContentCaptureEvent event = new ContentCaptureEvent(sessionId, TYPE_VIEW_APPEARED)
.setViewNode(node.mNode);
- mHandler.post(() -> sendEvent(event));
+ enqueueEvent(event);
}
@Override
void internalNotifyViewDisappeared(int sessionId, @NonNull AutofillId id) {
final ContentCaptureEvent event = new ContentCaptureEvent(sessionId, TYPE_VIEW_DISAPPEARED)
.setAutofillId(id);
- mHandler.post(() -> sendEvent(event));
+ enqueueEvent(event);
}
@Override
@@ -780,7 +805,7 @@
.setAutofillId(id).setText(eventText)
.setComposingIndex(composingStart, composingEnd)
.setSelectionIndex(startIndex, endIndex);
- mHandler.post(() -> sendEvent(event));
+ enqueueEvent(event);
}
@Override
@@ -788,7 +813,7 @@
final ContentCaptureEvent event =
new ContentCaptureEvent(sessionId, TYPE_VIEW_INSETS_CHANGED)
.setInsets(viewInsets);
- mHandler.post(() -> sendEvent(event));
+ enqueueEvent(event);
}
@Override
@@ -798,19 +823,19 @@
final boolean forceFlush = disableFlush ? !started : FORCE_FLUSH;
final ContentCaptureEvent event = new ContentCaptureEvent(sessionId, type);
- mHandler.post(() -> sendEvent(event, FORCE_FLUSH));
+ enqueueEvent(event, forceFlush);
}
@Override
public void internalNotifySessionResumed() {
final ContentCaptureEvent event = new ContentCaptureEvent(mId, TYPE_SESSION_RESUMED);
- mHandler.post(() -> sendEvent(event, FORCE_FLUSH));
+ enqueueEvent(event, FORCE_FLUSH);
}
@Override
public void internalNotifySessionPaused() {
final ContentCaptureEvent event = new ContentCaptureEvent(mId, TYPE_SESSION_PAUSED);
- mHandler.post(() -> sendEvent(event, FORCE_FLUSH));
+ enqueueEvent(event, FORCE_FLUSH);
}
@Override
@@ -818,12 +843,16 @@
return super.isContentCaptureEnabled() && mManager.isContentCaptureEnabled();
}
- @Override
+ // Called by ContentCaptureManager.isContentCaptureEnabled
boolean isDisabled() {
return mDisabled.get();
}
- @Override
+ /**
+ * Sets the disabled state of content capture.
+ *
+ * @return whether disabled state was changed.
+ */
boolean setDisabled(boolean disabled) {
return mDisabled.compareAndSet(!disabled, disabled);
}
@@ -835,7 +864,7 @@
new ContentCaptureEvent(childSessionId, TYPE_SESSION_STARTED)
.setParentSessionId(parentSessionId)
.setClientContext(clientContext);
- mHandler.post(() -> sendEvent(event, FORCE_FLUSH));
+ enqueueEvent(event, FORCE_FLUSH);
}
@Override
@@ -843,14 +872,14 @@
final ContentCaptureEvent event =
new ContentCaptureEvent(childSessionId, TYPE_SESSION_FINISHED)
.setParentSessionId(parentSessionId);
- mHandler.post(() -> sendEvent(event, FORCE_FLUSH));
+ enqueueEvent(event, FORCE_FLUSH);
}
@Override
void internalNotifyContextUpdated(int sessionId, @Nullable ContentCaptureContext context) {
final ContentCaptureEvent event = new ContentCaptureEvent(sessionId, TYPE_CONTEXT_UPDATED)
.setClientContext(context);
- mHandler.post(() -> sendEvent(event, FORCE_FLUSH));
+ enqueueEvent(event, FORCE_FLUSH);
}
@Override
@@ -858,18 +887,97 @@
final ContentCaptureEvent event =
new ContentCaptureEvent(sessionId, TYPE_WINDOW_BOUNDS_CHANGED)
.setBounds(bounds);
- mHandler.post(() -> sendEvent(event));
+ enqueueEvent(event);
+ }
+
+ private List<ContentCaptureEvent> clearBufferEvents() {
+ final ArrayList<ContentCaptureEvent> bufferEvents = new ArrayList<>();
+ ContentCaptureEvent event;
+ while ((event = mEventProcessQueue.poll()) != null) {
+ bufferEvents.add(event);
+ }
+ return bufferEvents;
+ }
+
+ private void enqueueEvent(@NonNull final ContentCaptureEvent event) {
+ enqueueEvent(event, /* forceFlush */ false);
+ }
+
+ /**
+ * Enqueue the event into {@code mEventProcessBuffer} if it is not an urgent request. Otherwise,
+ * clear the buffer events then starting sending out current event.
+ */
+ private void enqueueEvent(@NonNull final ContentCaptureEvent event, boolean forceFlush) {
+ if (forceFlush || mEventProcessQueue.size() >= mManager.mOptions.maxBufferSize - 1) {
+ // The buffer events are cleared in the same thread first to prevent new events
+ // being added during the time of context switch. This would disrupt the sequence
+ // of events.
+ final List<ContentCaptureEvent> batchEvents = clearBufferEvents();
+ runOnContentCaptureThread(() -> {
+ for (int i = 0; i < batchEvents.size(); i++) {
+ sendEvent(batchEvents.get(i));
+ }
+ sendEvent(event, /* forceFlush= */ true);
+ });
+ } else {
+ mEventProcessQueue.offer(event);
+ }
}
@Override
public void notifyContentCaptureEvents(
@NonNull SparseArray<ArrayList<Object>> contentCaptureEvents) {
- notifyContentCaptureEventsImpl(contentCaptureEvents);
+ runOnUiThread(() -> {
+ prepareViewStructures(contentCaptureEvents);
+ runOnContentCaptureThread(() ->
+ notifyContentCaptureEventsImpl(contentCaptureEvents));
+ });
+ }
+
+ /**
+ * Traverse events and pre-process {@link View} events to {@link ViewStructureSession} events.
+ * If a {@link View} event is invalid, an empty {@link ViewStructureSession} will still be
+ * provided.
+ */
+ private void prepareViewStructures(
+ @NonNull SparseArray<ArrayList<Object>> contentCaptureEvents) {
+ for (int i = 0; i < contentCaptureEvents.size(); i++) {
+ int sessionId = contentCaptureEvents.keyAt(i);
+ ArrayList<Object> events = contentCaptureEvents.valueAt(i);
+ for_each_event: for (int j = 0; j < events.size(); j++) {
+ Object event = events.get(j);
+ if (event instanceof View) {
+ View view = (View) event;
+ ContentCaptureSession session = view.getContentCaptureSession();
+ ViewStructureSession structureSession = new ViewStructureSession();
+
+ // Replace the View event with ViewStructureSession no matter the data is
+ // available or not. This is to ensure the sequence of the events are still
+ // the same. Calls to notifyViewAppeared will check the availability later.
+ events.set(j, structureSession);
+ if (session == null) {
+ Log.w(TAG, "no content capture session on view: " + view);
+ continue for_each_event;
+ }
+ int actualId = session.getId();
+ if (actualId != sessionId) {
+ Log.w(TAG, "content capture session mismatch for view (" + view
+ + "): was " + sessionId + " before, it's " + actualId + " now");
+ continue for_each_event;
+ }
+ ViewStructure structure = session.newViewStructure(view);
+ view.onProvideContentCaptureStructure(structure, /* flags= */ 0);
+
+ structureSession.setSession(session);
+ structureSession.setStructure(structure);
+ }
+ }
+ }
}
private void notifyContentCaptureEventsImpl(
@NonNull SparseArray<ArrayList<Object>> contentCaptureEvents) {
- checkOnUiThread();
+ checkOnContentCaptureThread();
try {
if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "notifyContentCaptureEvents");
@@ -882,22 +990,8 @@
Object event = events.get(j);
if (event instanceof AutofillId) {
internalNotifyViewDisappeared(sessionId, (AutofillId) event);
- } else if (event instanceof View) {
- View view = (View) event;
- ContentCaptureSession session = view.getContentCaptureSession();
- if (session == null) {
- Log.w(TAG, "no content capture session on view: " + view);
- continue for_each_event;
- }
- int actualId = session.getId();
- if (actualId != sessionId) {
- Log.w(TAG, "content capture session mismatch for view (" + view
- + "): was " + sessionId + " before, it's " + actualId + " now");
- continue for_each_event;
- }
- ViewStructure structure = session.newViewStructure(view);
- view.onProvideContentCaptureStructure(structure, /* flags= */ 0);
- session.notifyViewAppeared(structure);
+ } else if (event instanceof ViewStructureSession viewStructureSession) {
+ viewStructureSession.notifyViewAppeared();
} else if (event instanceof Insets) {
internalNotifyViewInsetsChanged(sessionId, (Insets) event);
} else {
@@ -1015,9 +1109,9 @@
* Therefore, accessing internal properties in {@link MainContentCaptureSession} should
* always delegate to the assigned thread from {@code mHandler} for synchronization.</p>
*/
- private void checkOnUiThread() {
- final boolean onUiThread = mHandler.getLooper().isCurrentThread();
- if (!onUiThread) {
+ private void checkOnContentCaptureThread() {
+ final boolean onContentCaptureThread = mContentCaptureHandler.getLooper().isCurrentThread();
+ if (!onContentCaptureThread) {
mWrongThreadCount.incrementAndGet();
Log.e(TAG, "MainContentCaptureSession running on " + Thread.currentThread());
}
@@ -1028,4 +1122,63 @@
Counter.logIncrement(
CONTENT_CAPTURE_WRONG_THREAD_METRIC_ID, mWrongThreadCount.getAndSet(0));
}
+
+ /**
+ * Ensures that {@code r} will be running on the assigned thread.
+ *
+ * <p>This is to prevent unnecessary delegation to Handler that results in fragmented runnable.
+ * </p>
+ */
+ private void runOnContentCaptureThread(@NonNull Runnable r) {
+ if (!mContentCaptureHandler.getLooper().isCurrentThread()) {
+ mContentCaptureHandler.post(r);
+ } else {
+ r.run();
+ }
+ }
+
+ private void clearAndRunOnContentCaptureThread(@NonNull Runnable r, int what) {
+ if (!mContentCaptureHandler.getLooper().isCurrentThread()) {
+ mContentCaptureHandler.removeMessages(what);
+ mContentCaptureHandler.post(r);
+ } else {
+ r.run();
+ }
+ }
+
+ private void runOnUiThread(@NonNull Runnable r) {
+ if (mUiHandler.getLooper().isCurrentThread()) {
+ r.run();
+ } else {
+ mUiHandler.post(r);
+ }
+ }
+
+ /**
+ * Holds {@link ContentCaptureSession} and related {@link ViewStructure} for processing.
+ */
+ private static final class ViewStructureSession {
+ @Nullable private ContentCaptureSession mSession;
+ @Nullable private ViewStructure mStructure;
+
+ ViewStructureSession() {}
+
+ void setSession(@Nullable ContentCaptureSession session) {
+ this.mSession = session;
+ }
+
+ void setStructure(@Nullable ViewStructure struct) {
+ this.mStructure = struct;
+ }
+
+ /**
+ * Calls {@link ContentCaptureSession#notifyViewAppeared(ViewStructure)} if the session and
+ * the view structure are available.
+ */
+ void notifyViewAppeared() {
+ if (mSession != null && mStructure != null) {
+ mSession.notifyViewAppeared(mStructure);
+ }
+ }
+ }
}
diff --git a/core/java/android/view/contentcapture/MainContentCaptureSessionV2.java b/core/java/android/view/contentcapture/MainContentCaptureSessionV2.java
deleted file mode 100644
index fbb66d1..0000000
--- a/core/java/android/view/contentcapture/MainContentCaptureSessionV2.java
+++ /dev/null
@@ -1,1187 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.view.contentcapture;
-
-import static android.view.contentcapture.ContentCaptureEvent.TYPE_CONTEXT_UPDATED;
-import static android.view.contentcapture.ContentCaptureEvent.TYPE_SESSION_FINISHED;
-import static android.view.contentcapture.ContentCaptureEvent.TYPE_SESSION_PAUSED;
-import static android.view.contentcapture.ContentCaptureEvent.TYPE_SESSION_RESUMED;
-import static android.view.contentcapture.ContentCaptureEvent.TYPE_SESSION_STARTED;
-import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_APPEARED;
-import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_DISAPPEARED;
-import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_INSETS_CHANGED;
-import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_TEXT_CHANGED;
-import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_TREE_APPEARED;
-import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_TREE_APPEARING;
-import static android.view.contentcapture.ContentCaptureEvent.TYPE_WINDOW_BOUNDS_CHANGED;
-import static android.view.contentcapture.ContentCaptureHelper.getSanitizedString;
-import static android.view.contentcapture.ContentCaptureHelper.sDebug;
-import static android.view.contentcapture.ContentCaptureHelper.sVerbose;
-import static android.view.contentcapture.ContentCaptureManager.RESULT_CODE_FALSE;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.ComponentName;
-import android.content.pm.ParceledListSlice;
-import android.graphics.Insets;
-import android.graphics.Rect;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.IBinder.DeathRecipient;
-import android.os.RemoteException;
-import android.os.Trace;
-import android.service.contentcapture.ContentCaptureService;
-import android.text.Selection;
-import android.text.Spannable;
-import android.text.TextUtils;
-import android.util.LocalLog;
-import android.util.Log;
-import android.util.SparseArray;
-import android.util.TimeUtils;
-import android.view.View;
-import android.view.ViewStructure;
-import android.view.autofill.AutofillId;
-import android.view.contentcapture.ViewNode.ViewStructureImpl;
-import android.view.contentprotection.ContentProtectionEventProcessor;
-import android.view.inputmethod.BaseInputConnection;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.os.IResultReceiver;
-import com.android.modules.expresslog.Counter;
-
-import java.io.PrintWriter;
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.NoSuchElementException;
-import java.util.concurrent.ConcurrentLinkedQueue;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
-
-/**
- * Main session associated with a context.
- *
- * <p>This is forked from {@link MainContentCaptureSession} to hold the logic of running operations
- * in the background thread.</p>
- *
- * @hide
- */
-@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
-public final class MainContentCaptureSessionV2 extends ContentCaptureSession {
-
- private static final String TAG = MainContentCaptureSession.class.getSimpleName();
-
- private static final String CONTENT_CAPTURE_WRONG_THREAD_METRIC_ID =
- "content_capture.value_content_capture_wrong_thread_count";
-
- // For readability purposes...
- private static final boolean FORCE_FLUSH = true;
-
- /**
- * Handler message used to flush the buffer.
- */
- private static final int MSG_FLUSH = 1;
-
- @NonNull
- private final AtomicBoolean mDisabled = new AtomicBoolean(false);
-
- @NonNull
- private final ContentCaptureManager.StrippedContext mContext;
-
- @NonNull
- private final ContentCaptureManager mManager;
-
- @NonNull
- private final Handler mUiHandler;
-
- @NonNull
- private final Handler mContentCaptureHandler;
-
- /**
- * Interface to the system_server binder object - it's only used to start the session (and
- * notify when the session is finished).
- */
- @NonNull
- private final IContentCaptureManager mSystemServerInterface;
-
- /**
- * Direct interface to the service binder object - it's used to send the events, including the
- * last ones (when the session is finished)
- *
- * @hide
- */
- @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
- @Nullable
- public IContentCaptureDirectManager mDirectServiceInterface;
-
- @Nullable
- private DeathRecipient mDirectServiceVulture;
-
- private int mState = UNKNOWN_STATE;
-
- @Nullable
- private IBinder mApplicationToken;
- @Nullable
- private IBinder mShareableActivityToken;
-
- /** @hide */
- @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
- @Nullable
- public ComponentName mComponentName;
-
- /**
- * Thread-safe queue of events held to be processed as a batch.
- *
- * Because it is not guaranteed that the events will be enqueued from a single thread, the
- * implementation must be thread-safe to prevent unexpected behaviour.
- *
- * @hide
- */
- @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
- @NonNull
- public final ConcurrentLinkedQueue<ContentCaptureEvent> mEventProcessQueue;
-
- /**
- * List of events held to be sent to the {@link ContentCaptureService} as a batch.
- *
- * @hide
- */
- @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
- @Nullable
- public ArrayList<ContentCaptureEvent> mEvents;
-
- // Used just for debugging purposes (on dump)
- private long mNextFlush;
-
- /**
- * Whether the next buffer flush is queued by a text changed event.
- */
- private boolean mNextFlushForTextChanged = false;
-
- @Nullable
- private final LocalLog mFlushHistory;
-
- private final AtomicInteger mWrongThreadCount = new AtomicInteger(0);
-
- /**
- * Binder object used to update the session state.
- */
- @NonNull
- private final SessionStateReceiver mSessionStateReceiver;
-
- /** @hide */
- @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
- @Nullable
- public ContentProtectionEventProcessor mContentProtectionEventProcessor;
-
- private static class SessionStateReceiver extends IResultReceiver.Stub {
- private final WeakReference<MainContentCaptureSessionV2> mMainSession;
-
- SessionStateReceiver(MainContentCaptureSessionV2 session) {
- mMainSession = new WeakReference<>(session);
- }
-
- @Override
- public void send(int resultCode, Bundle resultData) {
- final MainContentCaptureSessionV2 mainSession = mMainSession.get();
- if (mainSession == null) {
- Log.w(TAG, "received result after mina session released");
- return;
- }
- final IBinder binder;
- if (resultData != null) {
- // Change in content capture enabled.
- final boolean hasEnabled = resultData.getBoolean(EXTRA_ENABLED_STATE);
- if (hasEnabled) {
- final boolean disabled = (resultCode == RESULT_CODE_FALSE);
- mainSession.mDisabled.set(disabled);
- return;
- }
- binder = resultData.getBinder(EXTRA_BINDER);
- if (binder == null) {
- Log.wtf(TAG, "No " + EXTRA_BINDER + " extra result");
- mainSession.runOnContentCaptureThread(() -> mainSession.resetSession(
- STATE_DISABLED | STATE_INTERNAL_ERROR));
- return;
- }
- } else {
- binder = null;
- }
- mainSession.runOnContentCaptureThread(() ->
- mainSession.onSessionStarted(resultCode, binder));
- }
- }
-
- /** @hide */
- @VisibleForTesting(visibility = VisibleForTesting.Visibility.PROTECTED)
- public MainContentCaptureSessionV2(
- @NonNull ContentCaptureManager.StrippedContext context,
- @NonNull ContentCaptureManager manager,
- @NonNull Handler uiHandler,
- @NonNull Handler contentCaptureHandler,
- @NonNull IContentCaptureManager systemServerInterface) {
- mContext = context;
- mManager = manager;
- mUiHandler = uiHandler;
- mContentCaptureHandler = contentCaptureHandler;
- mSystemServerInterface = systemServerInterface;
-
- final int logHistorySize = mManager.mOptions.logHistorySize;
- mFlushHistory = logHistorySize > 0 ? new LocalLog(logHistorySize) : null;
-
- mSessionStateReceiver = new SessionStateReceiver(this);
-
- mEventProcessQueue = new ConcurrentLinkedQueue<>();
- }
-
- @Override
- ContentCaptureSession getMainCaptureSession() {
- return this;
- }
-
- @Override
- ContentCaptureSession newChild(@NonNull ContentCaptureContext clientContext) {
- final ContentCaptureSession child = new ChildContentCaptureSession(this, clientContext);
- internalNotifyChildSessionStarted(mId, child.mId, clientContext);
- return child;
- }
-
- /**
- * Starts this session.
- */
- @Override
- void start(@NonNull IBinder token, @NonNull IBinder shareableActivityToken,
- @NonNull ComponentName component, int flags) {
- runOnContentCaptureThread(
- () -> startImpl(token, shareableActivityToken, component, flags));
- }
-
- private void startImpl(@NonNull IBinder token, @NonNull IBinder shareableActivityToken,
- @NonNull ComponentName component, int flags) {
- checkOnContentCaptureThread();
- if (!isContentCaptureEnabled()) return;
-
- if (sVerbose) {
- Log.v(TAG, "start(): token=" + token + ", comp="
- + ComponentName.flattenToShortString(component));
- }
-
- if (hasStarted()) {
- // TODO(b/122959591): make sure this is expected (and when), or use Log.w
- if (sDebug) {
- Log.d(TAG, "ignoring handleStartSession(" + token + "/"
- + ComponentName.flattenToShortString(component) + " while on state "
- + getStateAsString(mState));
- }
- return;
- }
- mState = STATE_WAITING_FOR_SERVER;
- mApplicationToken = token;
- mShareableActivityToken = shareableActivityToken;
- mComponentName = component;
-
- if (sVerbose) {
- Log.v(TAG, "handleStartSession(): token=" + token + ", act="
- + getDebugState() + ", id=" + mId);
- }
-
- try {
- mSystemServerInterface.startSession(mApplicationToken, mShareableActivityToken,
- component, mId, flags, mSessionStateReceiver);
- } catch (RemoteException e) {
- Log.w(TAG, "Error starting session for " + component.flattenToShortString() + ": " + e);
- }
- }
- @Override
- void onDestroy() {
- clearAndRunOnContentCaptureThread(() -> {
- try {
- flush(FLUSH_REASON_SESSION_FINISHED);
- } finally {
- destroySession();
- }
- }, MSG_FLUSH);
- }
-
- /**
- * Callback from {@code system_server} after call to {@link
- * IContentCaptureManager#startSession(IBinder, ComponentName, String, int, IResultReceiver)}.
- *
- * @param resultCode session state
- * @param binder handle to {@code IContentCaptureDirectManager}
- * @hide
- */
- @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
- public void onSessionStarted(int resultCode, @Nullable IBinder binder) {
- checkOnContentCaptureThread();
- if (binder != null) {
- mDirectServiceInterface = IContentCaptureDirectManager.Stub.asInterface(binder);
- mDirectServiceVulture = () -> {
- Log.w(TAG, "Keeping session " + mId + " when service died");
- mState = STATE_SERVICE_DIED;
- mDisabled.set(true);
- };
- try {
- binder.linkToDeath(mDirectServiceVulture, 0);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to link to death on " + binder + ": " + e);
- }
- }
-
- if (isContentProtectionEnabled()) {
- mContentProtectionEventProcessor =
- new ContentProtectionEventProcessor(
- mManager.getContentProtectionEventBuffer(),
- mContentCaptureHandler,
- mSystemServerInterface,
- mComponentName.getPackageName(),
- mManager.mOptions.contentProtectionOptions);
- } else {
- mContentProtectionEventProcessor = null;
- }
-
- if ((resultCode & STATE_DISABLED) != 0) {
- resetSession(resultCode);
- } else {
- mState = resultCode;
- mDisabled.set(false);
- // Flush any pending data immediately as buffering forced until now.
- flushIfNeeded(FLUSH_REASON_SESSION_CONNECTED);
- }
- if (sVerbose) {
- Log.v(TAG, "handleSessionStarted() result: id=" + mId + " resultCode=" + resultCode
- + ", state=" + getStateAsString(mState) + ", disabled=" + mDisabled.get()
- + ", binder=" + binder + ", events=" + (mEvents == null ? 0 : mEvents.size()));
- }
- }
-
- /** @hide */
- @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
- public void sendEvent(@NonNull ContentCaptureEvent event) {
- sendEvent(event, /* forceFlush= */ false);
- }
-
- private void sendEvent(@NonNull ContentCaptureEvent event, boolean forceFlush) {
- checkOnContentCaptureThread();
- final int eventType = event.getType();
- if (sVerbose) Log.v(TAG, "handleSendEvent(" + getDebugState() + "): " + event);
- if (!hasStarted() && eventType != ContentCaptureEvent.TYPE_SESSION_STARTED
- && eventType != ContentCaptureEvent.TYPE_CONTEXT_UPDATED) {
- // TODO(b/120494182): comment when this could happen (dialogs?)
- if (sVerbose) {
- Log.v(TAG, "handleSendEvent(" + getDebugState() + ", "
- + ContentCaptureEvent.getTypeAsString(eventType)
- + "): dropping because session not started yet");
- }
- return;
- }
- if (mDisabled.get()) {
- // This happens when the event was queued in the handler before the sesison was ready,
- // then handleSessionStarted() returned and set it as disabled - we need to drop it,
- // otherwise it will keep triggering handleScheduleFlush()
- if (sVerbose) Log.v(TAG, "handleSendEvent(): ignoring when disabled");
- return;
- }
-
- if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
- if (eventType == TYPE_VIEW_TREE_APPEARING) {
- Trace.asyncTraceBegin(
- Trace.TRACE_TAG_VIEW, /* methodName= */ "sendEventAsync", /* cookie= */ 0);
- }
- }
-
- if (isContentProtectionReceiverEnabled()) {
- sendContentProtectionEvent(event);
- }
- if (isContentCaptureReceiverEnabled()) {
- sendContentCaptureEvent(event, forceFlush);
- }
-
- if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
- if (eventType == TYPE_VIEW_TREE_APPEARED) {
- Trace.asyncTraceEnd(
- Trace.TRACE_TAG_VIEW, /* methodName= */ "sendEventAsync", /* cookie= */ 0);
- }
- }
- }
-
- private void sendContentProtectionEvent(@NonNull ContentCaptureEvent event) {
- checkOnContentCaptureThread();
- if (mContentProtectionEventProcessor != null) {
- mContentProtectionEventProcessor.processEvent(event);
- }
- }
-
- private void sendContentCaptureEvent(@NonNull ContentCaptureEvent event, boolean forceFlush) {
- checkOnContentCaptureThread();
- final int eventType = event.getType();
- final int maxBufferSize = mManager.mOptions.maxBufferSize;
- if (mEvents == null) {
- if (sVerbose) {
- Log.v(TAG, "handleSendEvent(): creating buffer for " + maxBufferSize + " events");
- }
- mEvents = new ArrayList<>(maxBufferSize);
- }
-
- // Some type of events can be merged together
- boolean addEvent = true;
-
- if (eventType == TYPE_VIEW_TEXT_CHANGED) {
- // We determine whether to add or merge the current event by following criteria:
- // 1. Don't have composing span: always add.
- // 2. Have composing span:
- // 2.1 either last or current text is empty: add.
- // 2.2 last event doesn't have composing span: add.
- // Otherwise, merge.
- final CharSequence text = event.getText();
- final boolean hasComposingSpan = event.hasComposingSpan();
- if (hasComposingSpan) {
- ContentCaptureEvent lastEvent = null;
- for (int index = mEvents.size() - 1; index >= 0; index--) {
- final ContentCaptureEvent tmpEvent = mEvents.get(index);
- if (event.getId().equals(tmpEvent.getId())) {
- lastEvent = tmpEvent;
- break;
- }
- }
- if (lastEvent != null && lastEvent.hasComposingSpan()) {
- final CharSequence lastText = lastEvent.getText();
- final boolean bothNonEmpty = !TextUtils.isEmpty(lastText)
- && !TextUtils.isEmpty(text);
- boolean equalContent =
- TextUtils.equals(lastText, text)
- && lastEvent.hasSameComposingSpan(event)
- && lastEvent.hasSameSelectionSpan(event);
- if (equalContent) {
- addEvent = false;
- } else if (bothNonEmpty) {
- lastEvent.mergeEvent(event);
- addEvent = false;
- }
- if (!addEvent && sVerbose) {
- Log.v(TAG, "Buffering VIEW_TEXT_CHANGED event, updated text="
- + getSanitizedString(text));
- }
- }
- }
- }
-
- if (!mEvents.isEmpty() && eventType == TYPE_VIEW_DISAPPEARED) {
- final ContentCaptureEvent lastEvent = mEvents.get(mEvents.size() - 1);
- if (lastEvent.getType() == TYPE_VIEW_DISAPPEARED
- && event.getSessionId() == lastEvent.getSessionId()) {
- if (sVerbose) {
- Log.v(TAG, "Buffering TYPE_VIEW_DISAPPEARED events for session "
- + lastEvent.getSessionId());
- }
- lastEvent.mergeEvent(event);
- addEvent = false;
- }
- }
-
- if (addEvent) {
- mEvents.add(event);
- }
-
- // TODO: we need to change when the flush happens so that we don't flush while the
- // composing span hasn't changed. But we might need to keep flushing the events for the
- // non-editable views and views that don't have the composing state; otherwise some other
- // Content Capture features may be delayed.
-
- final int numberEvents = mEvents.size();
-
- final boolean bufferEvent = numberEvents < maxBufferSize;
-
- if (bufferEvent && !forceFlush) {
- final int flushReason;
- if (eventType == TYPE_VIEW_TEXT_CHANGED) {
- mNextFlushForTextChanged = true;
- flushReason = FLUSH_REASON_TEXT_CHANGE_TIMEOUT;
- } else {
- if (mNextFlushForTextChanged) {
- if (sVerbose) {
- Log.i(TAG, "Not scheduling flush because next flush is for text changed");
- }
- return;
- }
-
- flushReason = FLUSH_REASON_IDLE_TIMEOUT;
- }
- scheduleFlush(flushReason, /* checkExisting= */ true);
- return;
- }
-
- if (mState != STATE_ACTIVE && numberEvents >= maxBufferSize) {
- // Callback from startSession hasn't been called yet - typically happens on system
- // apps that are started before the system service
- // TODO(b/122959591): try to ignore session while system is not ready / boot
- // not complete instead. Similarly, the manager service should return right away
- // when the user does not have a service set
- if (sDebug) {
- Log.d(TAG, "Closing session for " + getDebugState()
- + " after " + numberEvents + " delayed events");
- }
- resetSession(STATE_DISABLED | STATE_NO_RESPONSE);
- // TODO(b/111276913): denylist activity / use special flag to indicate that
- // when it's launched again
- return;
- }
- final int flushReason;
- switch (eventType) {
- case ContentCaptureEvent.TYPE_SESSION_STARTED:
- flushReason = FLUSH_REASON_SESSION_STARTED;
- break;
- case ContentCaptureEvent.TYPE_SESSION_FINISHED:
- flushReason = FLUSH_REASON_SESSION_FINISHED;
- break;
- case ContentCaptureEvent.TYPE_VIEW_TREE_APPEARING:
- flushReason = FLUSH_REASON_VIEW_TREE_APPEARING;
- break;
- case ContentCaptureEvent.TYPE_VIEW_TREE_APPEARED:
- flushReason = FLUSH_REASON_VIEW_TREE_APPEARED;
- break;
- default:
- flushReason = forceFlush ? FLUSH_REASON_FORCE_FLUSH : FLUSH_REASON_FULL;
- }
-
- flush(flushReason);
- }
-
- private boolean hasStarted() {
- checkOnContentCaptureThread();
- return mState != UNKNOWN_STATE;
- }
-
- private void scheduleFlush(@FlushReason int reason, boolean checkExisting) {
- checkOnContentCaptureThread();
- if (sVerbose) {
- Log.v(TAG, "handleScheduleFlush(" + getDebugState(reason)
- + ", checkExisting=" + checkExisting);
- }
- if (!hasStarted()) {
- if (sVerbose) Log.v(TAG, "handleScheduleFlush(): session not started yet");
- return;
- }
-
- if (mDisabled.get()) {
- // Should not be called on this state, as handleSendEvent checks.
- // But we rather add one if check and log than re-schedule and keep the session alive...
- Log.e(TAG, "handleScheduleFlush(" + getDebugState(reason) + "): should not be called "
- + "when disabled. events=" + (mEvents == null ? null : mEvents.size()));
- return;
- }
- if (checkExisting && mContentCaptureHandler.hasMessages(MSG_FLUSH)) {
- // "Renew" the flush message by removing the previous one
- mContentCaptureHandler.removeMessages(MSG_FLUSH);
- }
-
- final int flushFrequencyMs;
- if (reason == FLUSH_REASON_TEXT_CHANGE_TIMEOUT) {
- flushFrequencyMs = mManager.mOptions.textChangeFlushingFrequencyMs;
- } else {
- if (reason != FLUSH_REASON_IDLE_TIMEOUT) {
- if (sDebug) {
- Log.d(TAG, "handleScheduleFlush(" + getDebugState(reason) + "): not a timeout "
- + "reason because mDirectServiceInterface is not ready yet");
- }
- }
- flushFrequencyMs = mManager.mOptions.idleFlushingFrequencyMs;
- }
-
- mNextFlush = System.currentTimeMillis() + flushFrequencyMs;
- if (sVerbose) {
- Log.v(TAG, "handleScheduleFlush(): scheduled to flush in "
- + flushFrequencyMs + "ms: " + TimeUtils.logTimeOfDay(mNextFlush));
- }
- // Post using a Runnable directly to trim a few μs from PooledLambda.obtainMessage()
- mContentCaptureHandler.postDelayed(() ->
- flushIfNeeded(reason), MSG_FLUSH, flushFrequencyMs);
- }
-
- private void flushIfNeeded(@FlushReason int reason) {
- checkOnContentCaptureThread();
- if (mEvents == null || mEvents.isEmpty()) {
- if (sVerbose) Log.v(TAG, "Nothing to flush");
- return;
- }
- flush(reason);
- }
-
- /** @hide */
- @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
- @Override
- public void flush(@FlushReason int reason) {
- runOnContentCaptureThread(() -> flushImpl(reason));
- }
-
- private void flushImpl(@FlushReason int reason) {
- checkOnContentCaptureThread();
- if (mEvents == null || mEvents.size() == 0) {
- if (sVerbose) {
- Log.v(TAG, "Don't flush for empty event buffer.");
- }
- return;
- }
-
- if (mDisabled.get()) {
- Log.e(TAG, "handleForceFlush(" + getDebugState(reason) + "): should not be when "
- + "disabled");
- return;
- }
-
- if (!isContentCaptureReceiverEnabled()) {
- return;
- }
-
- if (mDirectServiceInterface == null) {
- if (sVerbose) {
- Log.v(TAG, "handleForceFlush(" + getDebugState(reason) + "): hold your horses, "
- + "client not ready: " + mEvents);
- }
- if (!mContentCaptureHandler.hasMessages(MSG_FLUSH)) {
- scheduleFlush(reason, /* checkExisting= */ false);
- }
- return;
- }
-
- mNextFlushForTextChanged = false;
-
- final int numberEvents = mEvents.size();
- final String reasonString = getFlushReasonAsString(reason);
-
- if (sVerbose) {
- ContentCaptureEvent event = mEvents.get(numberEvents - 1);
- String forceString = (reason == FLUSH_REASON_FORCE_FLUSH) ? ". The force flush event "
- + ContentCaptureEvent.getTypeAsString(event.getType()) : "";
- Log.v(TAG, "Flushing " + numberEvents + " event(s) for " + getDebugState(reason)
- + forceString);
- }
- if (mFlushHistory != null) {
- // Logs reason, size, max size, idle timeout
- final String logRecord = "r=" + reasonString + " s=" + numberEvents
- + " m=" + mManager.mOptions.maxBufferSize
- + " i=" + mManager.mOptions.idleFlushingFrequencyMs;
- mFlushHistory.log(logRecord);
- }
- try {
- mContentCaptureHandler.removeMessages(MSG_FLUSH);
-
- final ParceledListSlice<ContentCaptureEvent> events = clearEvents();
- mDirectServiceInterface.sendEvents(events, reason, mManager.mOptions);
- } catch (RemoteException e) {
- Log.w(TAG, "Error sending " + numberEvents + " for " + getDebugState()
- + ": " + e);
- }
- }
-
- @Override
- public void updateContentCaptureContext(@Nullable ContentCaptureContext context) {
- internalNotifyContextUpdated(mId, context);
- }
-
- /**
- * Resets the buffer and return a {@link ParceledListSlice} with the previous events.
- */
- @NonNull
- private ParceledListSlice<ContentCaptureEvent> clearEvents() {
- checkOnContentCaptureThread();
- // NOTE: we must save a reference to the current mEvents and then set it to to null,
- // otherwise clearing it would clear it in the receiving side if the service is also local.
- if (mEvents == null) {
- return new ParceledListSlice<>(Collections.EMPTY_LIST);
- }
-
- final List<ContentCaptureEvent> events = new ArrayList<>(mEvents);
- mEvents.clear();
- return new ParceledListSlice<>(events);
- }
-
- /** hide */
- @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
- public void destroySession() {
- checkOnContentCaptureThread();
- if (sDebug) {
- Log.d(TAG, "Destroying session (ctx=" + mContext + ", id=" + mId + ") with "
- + (mEvents == null ? 0 : mEvents.size()) + " event(s) for "
- + getDebugState());
- }
-
- reportWrongThreadMetric();
- try {
- mSystemServerInterface.finishSession(mId);
- } catch (RemoteException e) {
- Log.e(TAG, "Error destroying system-service session " + mId + " for "
- + getDebugState() + ": " + e);
- }
-
- if (mDirectServiceInterface != null) {
- mDirectServiceInterface.asBinder().unlinkToDeath(mDirectServiceVulture, 0);
- }
- mDirectServiceInterface = null;
- mContentProtectionEventProcessor = null;
- mEventProcessQueue.clear();
- }
-
- // TODO(b/122454205): once we support multiple sessions, we might need to move some of these
- // clearings out.
- /** @hide */
- @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
- public void resetSession(int newState) {
- checkOnContentCaptureThread();
- if (sVerbose) {
- Log.v(TAG, "handleResetSession(" + getActivityName() + "): from "
- + getStateAsString(mState) + " to " + getStateAsString(newState));
- }
- mState = newState;
- mDisabled.set((newState & STATE_DISABLED) != 0);
- // TODO(b/122454205): must reset children (which currently is owned by superclass)
- mApplicationToken = null;
- mShareableActivityToken = null;
- mComponentName = null;
- mEvents = null;
- if (mDirectServiceInterface != null) {
- try {
- mDirectServiceInterface.asBinder().unlinkToDeath(mDirectServiceVulture, 0);
- } catch (NoSuchElementException e) {
- Log.w(TAG, "IContentCaptureDirectManager does not exist");
- }
- }
- mDirectServiceInterface = null;
- mContentProtectionEventProcessor = null;
- mContentCaptureHandler.removeMessages(MSG_FLUSH);
- }
-
- @Override
- void internalNotifyViewAppeared(int sessionId, @NonNull ViewStructureImpl node) {
- final ContentCaptureEvent event = new ContentCaptureEvent(sessionId, TYPE_VIEW_APPEARED)
- .setViewNode(node.mNode);
- enqueueEvent(event);
- }
-
- @Override
- void internalNotifyViewDisappeared(int sessionId, @NonNull AutofillId id) {
- final ContentCaptureEvent event = new ContentCaptureEvent(sessionId, TYPE_VIEW_DISAPPEARED)
- .setAutofillId(id);
- enqueueEvent(event);
- }
-
- @Override
- void internalNotifyViewTextChanged(
- int sessionId, @NonNull AutofillId id, @Nullable CharSequence text) {
- // Since the same CharSequence instance may be reused in the TextView, we need to make
- // a copy of its content so that its value will not be changed by subsequent updates
- // in the TextView.
- CharSequence trimmed = TextUtils.trimToParcelableSize(text);
- final CharSequence eventText = trimmed != null && trimmed == text
- ? trimmed.toString()
- : trimmed;
-
- final int composingStart;
- final int composingEnd;
- if (text instanceof Spannable) {
- composingStart = BaseInputConnection.getComposingSpanStart((Spannable) text);
- composingEnd = BaseInputConnection.getComposingSpanEnd((Spannable) text);
- } else {
- composingStart = ContentCaptureEvent.MAX_INVALID_VALUE;
- composingEnd = ContentCaptureEvent.MAX_INVALID_VALUE;
- }
-
- final int startIndex = Selection.getSelectionStart(text);
- final int endIndex = Selection.getSelectionEnd(text);
-
- final ContentCaptureEvent event = new ContentCaptureEvent(sessionId, TYPE_VIEW_TEXT_CHANGED)
- .setAutofillId(id).setText(eventText)
- .setComposingIndex(composingStart, composingEnd)
- .setSelectionIndex(startIndex, endIndex);
- enqueueEvent(event);
- }
-
- @Override
- void internalNotifyViewInsetsChanged(int sessionId, @NonNull Insets viewInsets) {
- final ContentCaptureEvent event =
- new ContentCaptureEvent(sessionId, TYPE_VIEW_INSETS_CHANGED)
- .setInsets(viewInsets);
- enqueueEvent(event);
- }
-
- @Override
- public void internalNotifyViewTreeEvent(int sessionId, boolean started) {
- final int type = started ? TYPE_VIEW_TREE_APPEARING : TYPE_VIEW_TREE_APPEARED;
- final boolean disableFlush = mManager.getFlushViewTreeAppearingEventDisabled();
- final boolean forceFlush = disableFlush ? !started : FORCE_FLUSH;
-
- final ContentCaptureEvent event = new ContentCaptureEvent(sessionId, type);
- enqueueEvent(event, forceFlush);
- }
-
- @Override
- public void internalNotifySessionResumed() {
- final ContentCaptureEvent event = new ContentCaptureEvent(mId, TYPE_SESSION_RESUMED);
- enqueueEvent(event, FORCE_FLUSH);
- }
-
- @Override
- public void internalNotifySessionPaused() {
- final ContentCaptureEvent event = new ContentCaptureEvent(mId, TYPE_SESSION_PAUSED);
- enqueueEvent(event, FORCE_FLUSH);
- }
-
- @Override
- boolean isContentCaptureEnabled() {
- return super.isContentCaptureEnabled() && mManager.isContentCaptureEnabled();
- }
-
- // Called by ContentCaptureManager.isContentCaptureEnabled
- boolean isDisabled() {
- return mDisabled.get();
- }
-
- /**
- * Sets the disabled state of content capture.
- *
- * @return whether disabled state was changed.
- */
- boolean setDisabled(boolean disabled) {
- return mDisabled.compareAndSet(!disabled, disabled);
- }
-
- @Override
- void internalNotifyChildSessionStarted(int parentSessionId, int childSessionId,
- @NonNull ContentCaptureContext clientContext) {
- final ContentCaptureEvent event =
- new ContentCaptureEvent(childSessionId, TYPE_SESSION_STARTED)
- .setParentSessionId(parentSessionId)
- .setClientContext(clientContext);
- enqueueEvent(event, FORCE_FLUSH);
- }
-
- @Override
- void internalNotifyChildSessionFinished(int parentSessionId, int childSessionId) {
- final ContentCaptureEvent event =
- new ContentCaptureEvent(childSessionId, TYPE_SESSION_FINISHED)
- .setParentSessionId(parentSessionId);
- enqueueEvent(event, FORCE_FLUSH);
- }
-
- @Override
- void internalNotifyContextUpdated(int sessionId, @Nullable ContentCaptureContext context) {
- final ContentCaptureEvent event = new ContentCaptureEvent(sessionId, TYPE_CONTEXT_UPDATED)
- .setClientContext(context);
- enqueueEvent(event, FORCE_FLUSH);
- }
-
- @Override
- public void notifyWindowBoundsChanged(int sessionId, @NonNull Rect bounds) {
- final ContentCaptureEvent event =
- new ContentCaptureEvent(sessionId, TYPE_WINDOW_BOUNDS_CHANGED)
- .setBounds(bounds);
- enqueueEvent(event);
- }
-
- private List<ContentCaptureEvent> clearBufferEvents() {
- final ArrayList<ContentCaptureEvent> bufferEvents = new ArrayList<>();
- ContentCaptureEvent event;
- while ((event = mEventProcessQueue.poll()) != null) {
- bufferEvents.add(event);
- }
- return bufferEvents;
- }
-
- private void enqueueEvent(@NonNull final ContentCaptureEvent event) {
- enqueueEvent(event, /* forceFlush */ false);
- }
-
- /**
- * Enqueue the event into {@code mEventProcessBuffer} if it is not an urgent request. Otherwise,
- * clear the buffer events then starting sending out current event.
- */
- private void enqueueEvent(@NonNull final ContentCaptureEvent event, boolean forceFlush) {
- if (forceFlush || mEventProcessQueue.size() >= mManager.mOptions.maxBufferSize - 1) {
- // The buffer events are cleared in the same thread first to prevent new events
- // being added during the time of context switch. This would disrupt the sequence
- // of events.
- final List<ContentCaptureEvent> batchEvents = clearBufferEvents();
- runOnContentCaptureThread(() -> {
- for (int i = 0; i < batchEvents.size(); i++) {
- sendEvent(batchEvents.get(i));
- }
- sendEvent(event, /* forceFlush= */ true);
- });
- } else {
- mEventProcessQueue.offer(event);
- }
- }
-
- @Override
- public void notifyContentCaptureEvents(
- @NonNull SparseArray<ArrayList<Object>> contentCaptureEvents) {
- runOnUiThread(() -> {
- prepareViewStructures(contentCaptureEvents);
- runOnContentCaptureThread(() ->
- notifyContentCaptureEventsImpl(contentCaptureEvents));
- });
- }
-
- /**
- * Traverse events and pre-process {@link View} events to {@link ViewStructureSession} events.
- * If a {@link View} event is invalid, an empty {@link ViewStructureSession} will still be
- * provided.
- */
- private void prepareViewStructures(
- @NonNull SparseArray<ArrayList<Object>> contentCaptureEvents) {
- for (int i = 0; i < contentCaptureEvents.size(); i++) {
- int sessionId = contentCaptureEvents.keyAt(i);
- ArrayList<Object> events = contentCaptureEvents.valueAt(i);
- for_each_event: for (int j = 0; j < events.size(); j++) {
- Object event = events.get(j);
- if (event instanceof View) {
- View view = (View) event;
- ContentCaptureSession session = view.getContentCaptureSession();
- ViewStructureSession structureSession = new ViewStructureSession();
-
- // Replace the View event with ViewStructureSession no matter the data is
- // available or not. This is to ensure the sequence of the events are still
- // the same. Calls to notifyViewAppeared will check the availability later.
- events.set(j, structureSession);
- if (session == null) {
- Log.w(TAG, "no content capture session on view: " + view);
- continue for_each_event;
- }
- int actualId = session.getId();
- if (actualId != sessionId) {
- Log.w(TAG, "content capture session mismatch for view (" + view
- + "): was " + sessionId + " before, it's " + actualId + " now");
- continue for_each_event;
- }
- ViewStructure structure = session.newViewStructure(view);
- view.onProvideContentCaptureStructure(structure, /* flags= */ 0);
-
- structureSession.setSession(session);
- structureSession.setStructure(structure);
- }
- }
- }
- }
-
- private void notifyContentCaptureEventsImpl(
- @NonNull SparseArray<ArrayList<Object>> contentCaptureEvents) {
- checkOnContentCaptureThread();
- try {
- if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
- Trace.traceBegin(Trace.TRACE_TAG_VIEW, "notifyContentCaptureEvents");
- }
- for (int i = 0; i < contentCaptureEvents.size(); i++) {
- int sessionId = contentCaptureEvents.keyAt(i);
- internalNotifyViewTreeEvent(sessionId, /* started= */ true);
- ArrayList<Object> events = contentCaptureEvents.valueAt(i);
- for_each_event: for (int j = 0; j < events.size(); j++) {
- Object event = events.get(j);
- if (event instanceof AutofillId) {
- internalNotifyViewDisappeared(sessionId, (AutofillId) event);
- } else if (event instanceof ViewStructureSession viewStructureSession) {
- viewStructureSession.notifyViewAppeared();
- } else if (event instanceof Insets) {
- internalNotifyViewInsetsChanged(sessionId, (Insets) event);
- } else {
- Log.w(TAG, "invalid content capture event: " + event);
- }
- }
- internalNotifyViewTreeEvent(sessionId, /* started= */ false);
- }
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_VIEW);
- }
- }
-
- @Override
- void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
- super.dump(prefix, pw);
-
- pw.print(prefix); pw.print("mContext: "); pw.println(mContext);
- pw.print(prefix); pw.print("user: "); pw.println(mContext.getUserId());
- if (mDirectServiceInterface != null) {
- pw.print(prefix); pw.print("mDirectServiceInterface: ");
- pw.println(mDirectServiceInterface);
- }
- pw.print(prefix); pw.print("mDisabled: "); pw.println(mDisabled.get());
- pw.print(prefix); pw.print("isEnabled(): "); pw.println(isContentCaptureEnabled());
- pw.print(prefix); pw.print("state: "); pw.println(getStateAsString(mState));
- if (mApplicationToken != null) {
- pw.print(prefix); pw.print("app token: "); pw.println(mApplicationToken);
- }
- if (mShareableActivityToken != null) {
- pw.print(prefix); pw.print("sharable activity token: ");
- pw.println(mShareableActivityToken);
- }
- if (mComponentName != null) {
- pw.print(prefix); pw.print("component name: ");
- pw.println(mComponentName.flattenToShortString());
- }
- if (mEvents != null && !mEvents.isEmpty()) {
- final int numberEvents = mEvents.size();
- pw.print(prefix); pw.print("buffered events: "); pw.print(numberEvents);
- pw.print('/'); pw.println(mManager.mOptions.maxBufferSize);
- if (sVerbose && numberEvents > 0) {
- final String prefix3 = prefix + " ";
- for (int i = 0; i < numberEvents; i++) {
- final ContentCaptureEvent event = mEvents.get(i);
- pw.print(prefix3); pw.print(i); pw.print(": "); event.dump(pw);
- pw.println();
- }
- }
- pw.print(prefix); pw.print("mNextFlushForTextChanged: ");
- pw.println(mNextFlushForTextChanged);
- pw.print(prefix); pw.print("flush frequency: ");
- if (mNextFlushForTextChanged) {
- pw.println(mManager.mOptions.textChangeFlushingFrequencyMs);
- } else {
- pw.println(mManager.mOptions.idleFlushingFrequencyMs);
- }
- pw.print(prefix); pw.print("next flush: ");
- TimeUtils.formatDuration(mNextFlush - System.currentTimeMillis(), pw);
- pw.print(" ("); pw.print(TimeUtils.logTimeOfDay(mNextFlush)); pw.println(")");
- }
- if (mFlushHistory != null) {
- pw.print(prefix); pw.println("flush history:");
- mFlushHistory.reverseDump(/* fd= */ null, pw, /* args= */ null); pw.println();
- } else {
- pw.print(prefix); pw.println("not logging flush history");
- }
-
- super.dump(prefix, pw);
- }
-
- /**
- * Gets a string that can be used to identify the activity on logging statements.
- */
- private String getActivityName() {
- return mComponentName == null
- ? "pkg:" + mContext.getPackageName()
- : "act:" + mComponentName.flattenToShortString();
- }
-
- @NonNull
- private String getDebugState() {
- return getActivityName() + " [state=" + getStateAsString(mState) + ", disabled="
- + mDisabled.get() + "]";
- }
-
- @NonNull
- private String getDebugState(@FlushReason int reason) {
- return getDebugState() + ", reason=" + getFlushReasonAsString(reason);
- }
-
- private boolean isContentProtectionReceiverEnabled() {
- return mManager.mOptions.contentProtectionOptions.enableReceiver;
- }
-
- private boolean isContentCaptureReceiverEnabled() {
- return mManager.mOptions.enableReceiver;
- }
-
- private boolean isContentProtectionEnabled() {
- // Should not be possible for mComponentName to be null here but check anyway
- // Should not be possible for groups to be empty if receiver is enabled but check anyway
- return mManager.mOptions.contentProtectionOptions.enableReceiver
- && mManager.getContentProtectionEventBuffer() != null
- && mComponentName != null
- && (!mManager.mOptions.contentProtectionOptions.requiredGroups.isEmpty()
- || !mManager.mOptions.contentProtectionOptions.optionalGroups.isEmpty());
- }
-
- /**
- * Checks that the current work is running on the assigned thread from {@code mHandler} and
- * count the number of times running on the wrong thread.
- *
- * <p>It is not guaranteed that the callers always invoke function from a single thread.
- * Therefore, accessing internal properties in {@link MainContentCaptureSession} should
- * always delegate to the assigned thread from {@code mHandler} for synchronization.</p>
- */
- private void checkOnContentCaptureThread() {
- final boolean onContentCaptureThread = mContentCaptureHandler.getLooper().isCurrentThread();
- if (!onContentCaptureThread) {
- mWrongThreadCount.incrementAndGet();
- Log.e(TAG, "MainContentCaptureSession running on " + Thread.currentThread());
- }
- }
-
- /** Reports number of times running on the wrong thread. */
- private void reportWrongThreadMetric() {
- Counter.logIncrement(
- CONTENT_CAPTURE_WRONG_THREAD_METRIC_ID, mWrongThreadCount.getAndSet(0));
- }
-
- /**
- * Ensures that {@code r} will be running on the assigned thread.
- *
- * <p>This is to prevent unnecessary delegation to Handler that results in fragmented runnable.
- * </p>
- */
- private void runOnContentCaptureThread(@NonNull Runnable r) {
- if (!mContentCaptureHandler.getLooper().isCurrentThread()) {
- mContentCaptureHandler.post(r);
- } else {
- r.run();
- }
- }
-
- private void clearAndRunOnContentCaptureThread(@NonNull Runnable r, int what) {
- if (!mContentCaptureHandler.getLooper().isCurrentThread()) {
- mContentCaptureHandler.removeMessages(what);
- mContentCaptureHandler.post(r);
- } else {
- r.run();
- }
- }
-
- private void runOnUiThread(@NonNull Runnable r) {
- if (mUiHandler.getLooper().isCurrentThread()) {
- r.run();
- } else {
- mUiHandler.post(r);
- }
- }
-
- /**
- * Holds {@link ContentCaptureSession} and related {@link ViewStructure} for processing.
- */
- private static final class ViewStructureSession {
- @Nullable private ContentCaptureSession mSession;
- @Nullable private ViewStructure mStructure;
-
- ViewStructureSession() {}
-
- void setSession(@Nullable ContentCaptureSession session) {
- this.mSession = session;
- }
-
- void setStructure(@Nullable ViewStructure struct) {
- this.mStructure = struct;
- }
-
- /**
- * Calls {@link ContentCaptureSession#notifyViewAppeared(ViewStructure)} if the session and
- * the view structure are available.
- */
- void notifyViewAppeared() {
- if (mSession != null && mStructure != null) {
- mSession.notifyViewAppeared(mStructure);
- }
- }
- }
-}
diff --git a/core/java/android/widget/flags/notification_widget_flags.aconfig b/core/java/android/widget/flags/notification_widget_flags.aconfig
index 503e542..56a2cf7 100644
--- a/core/java/android/widget/flags/notification_widget_flags.aconfig
+++ b/core/java/android/widget/flags/notification_widget_flags.aconfig
@@ -57,3 +57,13 @@
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "conversation_layout_use_maximum_child_height"
+ namespace: "systemui"
+ description: "MessagingChild always needs to be measured during MessagingLinearLayout onMeasure."
+ bug: "324537506"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
\ No newline at end of file
diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java
index 8bd39fb..8ded608 100644
--- a/core/java/android/window/TransitionInfo.java
+++ b/core/java/android/window/TransitionInfo.java
@@ -663,6 +663,7 @@
private final Rect mStartAbsBounds = new Rect();
private final Rect mEndAbsBounds = new Rect();
private final Point mEndRelOffset = new Point();
+ private final Point mEndParentSize = new Point();
private ActivityManager.RunningTaskInfo mTaskInfo = null;
private boolean mAllowEnterPip;
private int mStartDisplayId = INVALID_DISPLAY;
@@ -697,6 +698,7 @@
mStartAbsBounds.readFromParcel(in);
mEndAbsBounds.readFromParcel(in);
mEndRelOffset.readFromParcel(in);
+ mEndParentSize.readFromParcel(in);
mTaskInfo = in.readTypedObject(ActivityManager.RunningTaskInfo.CREATOR);
mAllowEnterPip = in.readBoolean();
mStartDisplayId = in.readInt();
@@ -721,6 +723,7 @@
out.mStartAbsBounds.set(mStartAbsBounds);
out.mEndAbsBounds.set(mEndAbsBounds);
out.mEndRelOffset.set(mEndRelOffset);
+ out.mEndParentSize.set(mEndParentSize);
out.mTaskInfo = mTaskInfo;
out.mAllowEnterPip = mAllowEnterPip;
out.mStartDisplayId = mStartDisplayId;
@@ -781,6 +784,13 @@
}
/**
+ * Sets the size of its parent container after the change.
+ */
+ public void setEndParentSize(int width, int height) {
+ mEndParentSize.set(width, height);
+ }
+
+ /**
* Sets the taskinfo of this container if this is a task. WARNING: this takes the
* reference, so don't modify it afterwards.
*/
@@ -916,6 +926,14 @@
return mEndRelOffset;
}
+ /**
+ * Returns the size of parent container after the change.
+ */
+ @NonNull
+ public Point getEndParentSize() {
+ return mEndParentSize;
+ }
+
/** @return the leash or surface to animate for this container */
@NonNull
public SurfaceControl getLeash() {
@@ -1003,6 +1021,7 @@
mStartAbsBounds.writeToParcel(dest, flags);
mEndAbsBounds.writeToParcel(dest, flags);
mEndRelOffset.writeToParcel(dest, flags);
+ mEndParentSize.writeToParcel(dest, flags);
dest.writeTypedObject(mTaskInfo, flags);
dest.writeBoolean(mAllowEnterPip);
dest.writeInt(mStartDisplayId);
@@ -1055,6 +1074,9 @@
if (mEndRelOffset.x != 0 || mEndRelOffset.y != 0) {
sb.append(" eo="); sb.append(mEndRelOffset);
}
+ if (!mEndParentSize.equals(0, 0)) {
+ sb.append(" epz=").append(mEndParentSize);
+ }
sb.append(" d=");
if (mStartDisplayId != mEndDisplayId) {
sb.append(mStartDisplayId).append("->");
diff --git a/core/java/android/window/WindowOnBackInvokedDispatcher.java b/core/java/android/window/WindowOnBackInvokedDispatcher.java
index 4ca64e7..4fb6e69 100644
--- a/core/java/android/window/WindowOnBackInvokedDispatcher.java
+++ b/core/java/android/window/WindowOnBackInvokedDispatcher.java
@@ -37,6 +37,7 @@
import android.view.IWindowSession;
import android.view.ImeBackAnimationController;
import android.view.MotionEvent;
+import android.view.ViewRootImpl;
import androidx.annotation.VisibleForTesting;
@@ -49,6 +50,7 @@
import java.util.HashMap;
import java.util.Objects;
import java.util.TreeMap;
+import java.util.function.BooleanSupplier;
import java.util.function.Supplier;
/**
@@ -68,6 +70,7 @@
public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
private IWindowSession mWindowSession;
private IWindow mWindow;
+ private ViewRootImpl mViewRoot;
@VisibleForTesting
public final BackTouchTracker mTouchTracker = new BackTouchTracker();
@VisibleForTesting
@@ -134,10 +137,12 @@
* is attached a window.
*/
public void attachToWindow(@NonNull IWindowSession windowSession, @NonNull IWindow window,
+ @Nullable ViewRootImpl viewRoot,
@Nullable ImeBackAnimationController imeBackAnimationController) {
synchronized (mLock) {
mWindowSession = windowSession;
mWindow = window;
+ mViewRoot = viewRoot;
mImeBackAnimationController = imeBackAnimationController;
if (!mAllCallbacks.isEmpty()) {
setTopOnBackInvokedCallback(getTopCallback());
@@ -151,6 +156,7 @@
clear();
mWindow = null;
mWindowSession = null;
+ mViewRoot = null;
mImeBackAnimationController = null;
}
}
@@ -176,8 +182,6 @@
return;
}
if (callback instanceof ImeOnBackInvokedDispatcher.ImeOnBackInvokedCallback) {
- // Fall back to compat back key injection if legacy back behaviour should be used.
- if (!isOnBackInvokedCallbackEnabled()) return;
if (callback instanceof ImeOnBackInvokedDispatcher.DefaultImeOnBackAnimationCallback
&& mImeBackAnimationController != null) {
// register ImeBackAnimationController instead to play predictive back animation
@@ -300,6 +304,14 @@
}
}
+ private boolean callOnKeyPreIme() {
+ if (mViewRoot != null && !isOnBackInvokedCallbackEnabled(mViewRoot.mContext)) {
+ return mViewRoot.injectBackKeyEvents(/*preImeOnly*/ true);
+ } else {
+ return false;
+ }
+ }
+
private void setTopOnBackInvokedCallback(@Nullable OnBackInvokedCallback callback) {
if (mWindowSession == null || mWindow == null) {
return;
@@ -308,8 +320,8 @@
OnBackInvokedCallbackInfo callbackInfo = null;
if (callback != null) {
int priority = mAllCallbacks.get(callback);
- final IOnBackInvokedCallback iCallback = new OnBackInvokedCallbackWrapper(
- callback, mTouchTracker, mProgressAnimator, mHandler);
+ final IOnBackInvokedCallback iCallback = new OnBackInvokedCallbackWrapper(callback,
+ mTouchTracker, mProgressAnimator, mHandler, this::callOnKeyPreIme);
callbackInfo = new OnBackInvokedCallbackInfo(
iCallback,
priority,
@@ -399,16 +411,20 @@
private final BackTouchTracker mTouchTracker;
@NonNull
private final Handler mHandler;
+ @NonNull
+ private final BooleanSupplier mOnKeyPreIme;
OnBackInvokedCallbackWrapper(
@NonNull OnBackInvokedCallback callback,
@NonNull BackTouchTracker touchTracker,
@NonNull BackProgressAnimator progressAnimator,
- @NonNull Handler handler) {
+ @NonNull Handler handler,
+ @NonNull BooleanSupplier onKeyPreIme) {
mCallback = new WeakReference<>(callback);
mTouchTracker = touchTracker;
mProgressAnimator = progressAnimator;
mHandler = handler;
+ mOnKeyPreIme = onKeyPreIme;
}
@Override
@@ -460,6 +476,7 @@
public void onBackInvoked() throws RemoteException {
mHandler.post(() -> {
mTouchTracker.reset();
+ if (consumedByOnKeyPreIme()) return;
boolean isInProgress = mProgressAnimator.isBackAnimationInProgress();
final OnBackInvokedCallback callback = mCallback.get();
if (callback == null) {
@@ -481,6 +498,30 @@
});
}
+ private boolean consumedByOnKeyPreIme() {
+ final OnBackInvokedCallback callback = mCallback.get();
+ if (callback instanceof ImeBackAnimationController
+ || callback instanceof ImeOnBackInvokedDispatcher.ImeOnBackInvokedCallback) {
+ // call onKeyPreIme API if the current callback is an IME callback and the app has
+ // not set enableOnBackInvokedCallback="false"
+ try {
+ boolean consumed = mOnKeyPreIme.getAsBoolean();
+ if (consumed) {
+ // back event intercepted by app in onKeyPreIme -> cancel the IME animation.
+ final OnBackAnimationCallback animationCallback =
+ getBackAnimationCallback();
+ if (animationCallback != null) {
+ mProgressAnimator.onBackCancelled(animationCallback::onBackCancelled);
+ }
+ return true;
+ }
+ } catch (Exception e) {
+ Log.d(TAG, "Failed to call onKeyPreIme", e);
+ }
+ }
+ return false;
+ }
+
@Override
public void setTriggerBack(boolean triggerBack) throws RemoteException {
mTouchTracker.setTriggerBack(triggerBack);
diff --git a/core/java/com/android/internal/accessibility/util/AccessibilityUtils.java b/core/java/com/android/internal/accessibility/util/AccessibilityUtils.java
index e8472d4..0b1ecf7 100644
--- a/core/java/com/android/internal/accessibility/util/AccessibilityUtils.java
+++ b/core/java/com/android/internal/accessibility/util/AccessibilityUtils.java
@@ -126,7 +126,7 @@
}
/**
- * Changes an accessibility component's state.
+ * Changes an accessibility component's state for the calling process userId
*/
public static void setAccessibilityServiceState(Context context, ComponentName componentName,
boolean enabled) {
diff --git a/core/java/com/android/internal/accessibility/util/ShortcutUtils.java b/core/java/com/android/internal/accessibility/util/ShortcutUtils.java
index 5b09a8b..a7aef92 100644
--- a/core/java/com/android/internal/accessibility/util/ShortcutUtils.java
+++ b/core/java/com/android/internal/accessibility/util/ShortcutUtils.java
@@ -224,7 +224,9 @@
boolean enableA11yService = servicesWithShortcuts.contains(componentName);
AccessibilityUtils.setAccessibilityServiceState(
context,
- ComponentName.unflattenFromString(componentName), enableA11yService);
+ ComponentName.unflattenFromString(componentName),
+ enableA11yService,
+ userId);
}
}
}
diff --git a/core/java/com/android/internal/jank/Cuj.java b/core/java/com/android/internal/jank/Cuj.java
index 6ffa826..23bd64d 100644
--- a/core/java/com/android/internal/jank/Cuj.java
+++ b/core/java/com/android/internal/jank/Cuj.java
@@ -137,9 +137,18 @@
public static final int CUJ_LAUNCHER_PRIVATE_SPACE_LOCK = 102;
public static final int CUJ_LAUNCHER_PRIVATE_SPACE_UNLOCK = 103;
+ /**
+ * Track maximize window interaction in desktop mode.
+ *
+ * <p>Tracking starts onClick of the maximize window button or option {@link
+ * com.android.wm.shell.windowdecor.DesktopModeWindowDecorViewModel#onClick}
+ * and finishes when the window animation is ended {@link
+ * com.android.wm.shell.windowdecor.ToggleResizeDesktopTaskTransitionHandler#startAnimation}
+ */
+ public static final int CUJ_DESKTOP_MODE_MAXIMIZE_WINDOW = 104;
+
// When adding a CUJ, update this and make sure to also update CUJ_TO_STATSD_INTERACTION_TYPE.
- @VisibleForTesting
- static final int LAST_CUJ = CUJ_LAUNCHER_PRIVATE_SPACE_UNLOCK;
+ @VisibleForTesting static final int LAST_CUJ = CUJ_DESKTOP_MODE_MAXIMIZE_WINDOW;
/** @hide */
@IntDef({
@@ -234,11 +243,11 @@
CUJ_LAUNCHER_WIDGET_PICKER_SEARCH_BACK,
CUJ_LAUNCHER_WIDGET_BOTTOM_SHEET_CLOSE_BACK,
CUJ_LAUNCHER_PRIVATE_SPACE_LOCK,
- CUJ_LAUNCHER_PRIVATE_SPACE_UNLOCK
+ CUJ_LAUNCHER_PRIVATE_SPACE_UNLOCK,
+ CUJ_DESKTOP_MODE_MAXIMIZE_WINDOW
})
@Retention(RetentionPolicy.SOURCE)
- public @interface CujType {
- }
+ public @interface CujType {}
private static final int NO_STATSD_LOGGING = -1;
@@ -341,6 +350,7 @@
CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_WIDGET_EDU_SHEET_CLOSE_BACK] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_WIDGET_EDU_SHEET_CLOSE_BACK;
CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_PRIVATE_SPACE_LOCK] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_PRIVATE_SPACE_LOCK;
CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_PRIVATE_SPACE_UNLOCK] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_PRIVATE_SPACE_UNLOCK;
+ CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_DESKTOP_MODE_MAXIMIZE_WINDOW] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__DESKTOP_MODE_MAXIMIZE_WINDOW;
}
private Cuj() {
@@ -543,6 +553,8 @@
return "LAUNCHER_PRIVATE_SPACE_LOCK";
case CUJ_LAUNCHER_PRIVATE_SPACE_UNLOCK:
return "LAUNCHER_PRIVATE_SPACE_UNLOCK";
+ case CUJ_DESKTOP_MODE_MAXIMIZE_WINDOW:
+ return "DESKTOP_MODE_MAXIMIZE_WINDOW";
}
return "UNKNOWN";
}
diff --git a/core/java/com/android/internal/widget/ConversationLayout.java b/core/java/com/android/internal/widget/ConversationLayout.java
index bd654fa..2bfbf84 100644
--- a/core/java/com/android/internal/widget/ConversationLayout.java
+++ b/core/java/com/android/internal/widget/ConversationLayout.java
@@ -16,6 +16,8 @@
package com.android.internal.widget;
+import static android.widget.flags.Flags.conversationLayoutUseMaximumChildHeight;
+
import static com.android.internal.widget.MessagingGroup.IMAGE_DISPLAY_LOCATION_EXTERNAL;
import static com.android.internal.widget.MessagingGroup.IMAGE_DISPLAY_LOCATION_INLINE;
@@ -1407,6 +1409,38 @@
}
}
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+ // ConversationLayout needs to set its height to its biggest child to show the content
+ // properly.
+ // FrameLayout measures its match_parent children twice when any of FLs dimension is not
+ // specified. However, its sets its own dimensions before the second measurement pass.
+ // Content CutOff happens when children have bigger height on its second measurement.
+ if (conversationLayoutUseMaximumChildHeight()) {
+ int maxHeight = getMeasuredHeight();
+ final int count = getChildCount();
+
+ for (int i = 0; i < count; i++) {
+ final View child = getChildAt(i);
+ if (child == null || child.getVisibility() == GONE) {
+ continue;
+ }
+
+ final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+ maxHeight = Math.max(maxHeight,
+ child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);
+ }
+
+ maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
+ if (maxHeight != getMeasuredHeight()) {
+ setMeasuredDimension(getMeasuredWidth(), maxHeight);
+ }
+ }
+ }
+
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
diff --git a/core/java/com/android/internal/widget/NotificationRowIconView.java b/core/java/com/android/internal/widget/NotificationRowIconView.java
index 58bddae..f5f04a7 100644
--- a/core/java/com/android/internal/widget/NotificationRowIconView.java
+++ b/core/java/com/android/internal/widget/NotificationRowIconView.java
@@ -22,7 +22,12 @@
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
+import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
@@ -36,6 +41,13 @@
@RemoteViews.RemoteView
public class NotificationRowIconView extends CachingIconView {
private boolean mApplyCircularCrop = false;
+ private boolean mShouldShowAppIcon = false;
+
+ // Padding and background set on the view prior to being changed by setShouldShowAppIcon(true),
+ // to be restored if shouldShowAppIcon becomes false again.
+ private Rect mOriginalPadding = null;
+ private Drawable mOriginalBackground = null;
+
public NotificationRowIconView(Context context) {
super(context);
@@ -59,7 +71,7 @@
@Override
protected void onFinishInflate() {
// If showing the app icon, we don't need background or padding.
- if (Flags.notificationsUseAppIcon() || Flags.notificationsUseAppIconInRow()) {
+ if (Flags.notificationsUseAppIcon()) {
setPadding(0, 0, 0, 0);
setBackground(null);
}
@@ -67,6 +79,42 @@
super.onFinishInflate();
}
+ /** Whether the icon represents the app icon (instead of the small icon). */
+ @RemotableViewMethod
+ public void setShouldShowAppIcon(boolean shouldShowAppIcon) {
+ if (Flags.notificationsUseAppIconInRow()) {
+ if (mShouldShowAppIcon == shouldShowAppIcon) {
+ return; // no change
+ }
+
+ mShouldShowAppIcon = shouldShowAppIcon;
+ if (mShouldShowAppIcon) {
+ if (mOriginalPadding == null && mOriginalBackground == null) {
+ mOriginalPadding = new Rect(getPaddingLeft(), getPaddingTop(),
+ getPaddingRight(), getPaddingBottom());
+ mOriginalBackground = getBackground();
+ }
+
+ setPadding(0, 0, 0, 0);
+
+ // Make the background white in case the icon itself doesn't have one.
+ int white = Color.rgb(255, 255, 255);
+ ColorFilter colorFilter = new PorterDuffColorFilter(white,
+ PorterDuff.Mode.SRC_ATOP);
+ getBackground().mutate().setColorFilter(colorFilter);
+ } else {
+ // Restore original padding and background if needed
+ if (mOriginalPadding != null) {
+ setPadding(mOriginalPadding.left, mOriginalPadding.top, mOriginalPadding.right,
+ mOriginalPadding.bottom);
+ mOriginalPadding = null;
+ }
+ setBackground(mOriginalBackground);
+ mOriginalBackground = null;
+ }
+ }
+ }
+
@Nullable
@Override
Drawable loadSizeRestrictedIcon(@Nullable Icon icon) {
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 3c1ae77..b19bdf9 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -1883,8 +1883,7 @@
<string name="restr_pin_error_too_short" msgid="1547007808237941065">"PIN is too short. Must be at least 4 digits."</string>
<string name="restr_pin_try_later" msgid="5897719962541636727">"Try again later"</string>
<string name="immersive_cling_title" msgid="2307034298721541791">"Viewing full screen"</string>
- <!-- no translation found for immersive_cling_description (2896205051090870978) -->
- <skip />
+ <string name="immersive_cling_description" msgid="2896205051090870978">"To exit, swipe down from the top of your screen"</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Got it"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"Rotate for a better view"</string>
<string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"Open <xliff:g id="NAME">%s</xliff:g> in full screen for a better view"</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index 5572714..cb9bbf5 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -1883,8 +1883,7 @@
<string name="restr_pin_error_too_short" msgid="1547007808237941065">"PIN is too short. Must be at least 4 digits."</string>
<string name="restr_pin_try_later" msgid="5897719962541636727">"Try again later"</string>
<string name="immersive_cling_title" msgid="2307034298721541791">"Viewing full screen"</string>
- <!-- no translation found for immersive_cling_description (2896205051090870978) -->
- <skip />
+ <string name="immersive_cling_description" msgid="2896205051090870978">"To exit, swipe down from the top of your screen"</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Got it"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"Rotate for a better view"</string>
<string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"Open <xliff:g id="NAME">%s</xliff:g> in full screen for a better view"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 4d350a0..8fe9a5b 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -1433,7 +1433,7 @@
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"ભાષા અને લેઆઉટ પસંદ કરવા માટે ટૅપ કરો"</string>
<string name="fast_scroll_alphabet" msgid="8854435958703888376">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="2529539945421557329">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="alert_windows_notification_channel_group_name" msgid="6063891141815714246">"અન્ય ઍપથી ઉપર બતાવો"</string>
+ <string name="alert_windows_notification_channel_group_name" msgid="6063891141815714246">"અન્ય ઍપની ઉપર ડિસ્પ્લે કરો"</string>
<string name="alert_windows_notification_channel_name" msgid="3437528564303192620">"<xliff:g id="NAME">%s</xliff:g> અન્ય ઍપ્લિકેશનોની ઉપર પ્રદર્શિત થઈ રહ્યું છે"</string>
<string name="alert_windows_notification_title" msgid="6331662751095228536">"<xliff:g id="NAME">%s</xliff:g> અન્ય ઍપ્લિકેશનો પર દેખાઈ છે"</string>
<string name="alert_windows_notification_message" msgid="6538171456970725333">"જો તમે નથી ઇચ્છતા કે <xliff:g id="NAME">%s</xliff:g> આ સુવિધાનો ઉપયોગ કરે, તો સેટિંગ ખોલવા માટે ટૅપ કરો અને તેને બંધ કરો."</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index f4ed853..d305c87 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -209,7 +209,7 @@
<string name="location_changed_notification_text" msgid="7158423339982706912">"Контактирајте со IT-администраторот за да дознаете повеќе"</string>
<string name="geofencing_service" msgid="3826902410740315456">"Услуга за виртуелна географска граница"</string>
<string name="country_detector" msgid="7023275114706088854">"Детектор на земја"</string>
- <string name="location_service" msgid="2439187616018455546">"Услуга за локација"</string>
+ <string name="location_service" msgid="2439187616018455546">"Локациска услуга"</string>
<string name="gnss_service" msgid="8907781262179951385">"Услуга GNSS"</string>
<string name="sensor_notification_service" msgid="7474531979178682676">"Услуга за известување од сензорот"</string>
<string name="twilight_service" msgid="8964898045693187224">"Услуга за самрак"</string>
@@ -498,9 +498,9 @@
<string name="permlab_accessLocationExtraCommands" msgid="5162339812057983988">"пристапи кон наредби на давателот на дополнителна локација"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="355369611979907967">"Овозможува апликацијата да пристапи кон дополнителни наредби на давател на локација. Ова може да овозможи апликацијата да го попечи функционирањето на GPS или други извори на локација."</string>
<string name="permlab_accessFineLocation" msgid="6426318438195622966">"пристап до прецизната локација само во преден план"</string>
- <string name="permdesc_accessFineLocation" msgid="6732174080240016335">"Апликацијава може да ја добие вашата прецизна локација од „Услугите според локација“ кога се користи. „Услугите според локација“ за уредот мора да се вклучени ако сакате апликацијата да ја добие локацијата. Ова може да го зголеми користењето на батеријата."</string>
+ <string name="permdesc_accessFineLocation" msgid="6732174080240016335">"Апликацијава може да ја добие вашата прецизна локација од „Локациските услуги“ кога се користи. „Локациските услуги“ за уредот мора да се вклучени ако сакате апликацијата да ја добие локацијата. Ова може да го зголеми користењето на батеријата."</string>
<string name="permlab_accessCoarseLocation" msgid="1561042925407799741">"пристап до приближната локација само во преден план"</string>
- <string name="permdesc_accessCoarseLocation" msgid="778521847873199160">"Апликацијава може да ја добие вашата приближна локација од „Услугите според локација“ кога се користи. „Услугите според локација“ за уредот мора да се вклучени ако сакате апликацијата да ја добие локацијата."</string>
+ <string name="permdesc_accessCoarseLocation" msgid="778521847873199160">"Апликацијава може да ја добие вашата приближна локација од „Локациските услуги“ кога се користи. „Локациските услуги“ за уредот мора да се вклучени ако сакате апликацијата да ја добие локацијата."</string>
<string name="permlab_accessBackgroundLocation" msgid="1721164702777366138">"пристап до локацијата во заднина"</string>
<string name="permdesc_accessBackgroundLocation" msgid="8264885066095638105">"Апликацијава може да пристапува до локацијата во секое време, дури и кога не се користи."</string>
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"менува аудио поставки"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index bc6c99c..6bc9fe0 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -1380,7 +1380,7 @@
<string name="install_carrier_app_notification_title" msgid="5712723402213090102">"Ativar serviço móvel"</string>
<string name="install_carrier_app_notification_text" msgid="2781317581274192728">"Baixe o app da operadora para ativar seu novo chip"</string>
<string name="install_carrier_app_notification_text_app_name" msgid="4086877327264106484">"Baixe o app <xliff:g id="APP_NAME">%1$s</xliff:g> para ativar seu novo chip"</string>
- <string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Fazer download do app"</string>
+ <string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Baixar o app"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"Novo chip inserido"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"Toque para configurar"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"Definir hora"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index bc6c99c..6bc9fe0 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1380,7 +1380,7 @@
<string name="install_carrier_app_notification_title" msgid="5712723402213090102">"Ativar serviço móvel"</string>
<string name="install_carrier_app_notification_text" msgid="2781317581274192728">"Baixe o app da operadora para ativar seu novo chip"</string>
<string name="install_carrier_app_notification_text_app_name" msgid="4086877327264106484">"Baixe o app <xliff:g id="APP_NAME">%1$s</xliff:g> para ativar seu novo chip"</string>
- <string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Fazer download do app"</string>
+ <string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Baixar o app"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"Novo chip inserido"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"Toque para configurar"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"Definir hora"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index fe66eb9..5c3f819 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1433,7 +1433,7 @@
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"輕觸即可選取語言和版面配置"</string>
<string name="fast_scroll_alphabet" msgid="8854435958703888376">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="2529539945421557329">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="alert_windows_notification_channel_group_name" msgid="6063891141815714246">"顯示在其他應用程式上層"</string>
+ <string name="alert_windows_notification_channel_group_name" msgid="6063891141815714246">"在其他應用程式上面顯示"</string>
<string name="alert_windows_notification_channel_name" msgid="3437528564303192620">"「<xliff:g id="NAME">%s</xliff:g>」在其他應用程式上顯示內容"</string>
<string name="alert_windows_notification_title" msgid="6331662751095228536">"「<xliff:g id="NAME">%s</xliff:g>」正在其他應用程式上顯示內容"</string>
<string name="alert_windows_notification_message" msgid="6538171456970725333">"如果你不想讓「<xliff:g id="NAME">%s</xliff:g>」使用這項功能,請輕觸開啟設定頁面,然後停用此功能。"</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 4e133de..17666cf 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -5807,6 +5807,9 @@
<!-- The action name for the default profcollect report uploader app. -->
<string name="config_defaultProfcollectReportUploaderAction" translatable="false"></string>
+ <!-- Names of packages excluded by Profcollect onCameraOpened observer. -->
+ <string-array name="config_profcollectOnCameraOpenedSkipPackages" translatable="false"></string-array>
+
<!-- The default value used for RawContacts.ACCOUNT_NAME when contacts are inserted without this
column set. These contacts are stored locally on the device and will not be removed even
if no android.account.Account with this name exists. A null string will be used if the
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 7251d74..85397fa 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -4444,6 +4444,7 @@
<java-symbol type="bool" name="config_profcollectReportUploaderEnabled" />
<java-symbol type="string" name="config_defaultProfcollectReportUploaderApp" />
<java-symbol type="string" name="config_defaultProfcollectReportUploaderAction" />
+ <java-symbol type="array" name="config_profcollectOnCameraOpenedSkipPackages" />
<java-symbol type="string" name="usb_device_resolve_prompt_warn" />
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/ConversionUtilsTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/ConversionUtilsTest.java
index 86a6744..5a08acd 100644
--- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/ConversionUtilsTest.java
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/ConversionUtilsTest.java
@@ -255,6 +255,17 @@
}
@Test
+ public void throwOnError_withUnknownErrorCode() {
+ int invalidErrorCode = 100;
+ ServiceSpecificException halException = new ServiceSpecificException(invalidErrorCode);
+
+ RuntimeException thrown = ConversionUtils.throwOnError(halException, "seek");
+
+ expect.withMessage("Exception thrown for unknown error code")
+ .that(thrown).hasMessageThat().contains("seek: unknown error");
+ }
+
+ @Test
public void propertiesFromHalProperties_idsMatch() {
expect.withMessage("Properties id")
.that(MODULE_PROPERTIES.getId()).isEqualTo(TEST_ID);
@@ -296,7 +307,7 @@
Map<String, Integer> dabTableExpected = Map.of(DAB_ENTRY_LABEL_1, DAB_ENTRY_FREQUENCY_1,
DAB_ENTRY_LABEL_2, DAB_ENTRY_FREQUENCY_2);
- expect.withMessage("Supported program types")
+ expect.withMessage("DAB frequency table")
.that(MODULE_PROPERTIES.getDabFrequencyTable())
.containsExactlyEntriesIn(dabTableExpected);
}
@@ -621,7 +632,7 @@
@Test
public void programInfoMeetsSdkVersionRequirement_withLowerVersionIdForRelatedContent() {
RadioManager.ProgramInfo dabProgramInfo = new RadioManager.ProgramInfo(
- TEST_DAB_SELECTOR_LEGACY, TEST_DAB_SID_EXT_ID, TEST_DAB_FREQUENCY_ID,
+ TEST_DAB_SELECTOR_LEGACY, TEST_DAB_SID_EXT_LEGACY_ID, TEST_DAB_FREQUENCY_ID,
List.of(TEST_DAB_SID_EXT_ID), /* infoFlags= */ 0, TEST_SIGNAL_QUALITY,
new RadioMetadata.Builder().build(), new ArrayMap<>());
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/ConvertTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/ConvertTest.java
index 98641ef..c5c3a61 100644
--- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/ConvertTest.java
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/ConvertTest.java
@@ -32,6 +32,7 @@
import android.hardware.radio.ProgramSelector;
import android.hardware.radio.RadioManager;
import android.hardware.radio.RadioMetadata;
+import android.os.ParcelableException;
import android.util.ArrayMap;
import com.google.common.truth.Expect;
@@ -89,6 +90,15 @@
}
@Test
+ public void throwOnError_withUnknownErrorCode() {
+ ParcelableException thrown = assertThrows(ParcelableException.class, () ->
+ Convert.throwOnError("tune", /* result= */ 1000));
+
+ expect.withMessage("Exception for unknown error code").that(thrown)
+ .hasMessageThat().contains("unknown error");
+ }
+
+ @Test
public void propertiesFromHalProperties_idsMatch() {
expect.withMessage("Properties id")
.that(MODULE_PROPERTIES.getId()).isEqualTo(TEST_ID);
@@ -232,6 +242,12 @@
}
@Test
+ public void vendorInfoFromHalVendorKeyValues_withNull() {
+ expect.withMessage("Null vendor info converted from HAL")
+ .that(Convert.vendorInfoFromHal(/* info= */ null)).isEmpty();
+ }
+
+ @Test
public void vendorInfoFromHalVendorKeyValues_withNullElements() {
VendorKeyValue halVendorInfo = new VendorKeyValue();
halVendorInfo.key = null;
diff --git a/core/tests/coretests/src/android/app/NotificationTest.java b/core/tests/coretests/src/android/app/NotificationTest.java
index b64eeca..e9ad1c2 100644
--- a/core/tests/coretests/src/android/app/NotificationTest.java
+++ b/core/tests/coretests/src/android/app/NotificationTest.java
@@ -804,6 +804,7 @@
}
@Test
+ @Ignore // b/347089000 - Restore or delete
public void testColors_ensureColors_colorized_producesValidPalette_white() {
validateColorizedPaletteForColor(Color.WHITE);
}
diff --git a/core/tests/coretests/src/android/content/ContentResolverTest.java b/core/tests/coretests/src/android/content/ContentResolverTest.java
index 7b70b41..c8015d4 100644
--- a/core/tests/coretests/src/android/content/ContentResolverTest.java
+++ b/core/tests/coretests/src/android/content/ContentResolverTest.java
@@ -87,7 +87,7 @@
bitmap.compress(Bitmap.CompressFormat.PNG, 90, mImage.getOutputStream());
final AssetFileDescriptor afd = new AssetFileDescriptor(
- new ParcelFileDescriptor(mImage.getFileDescriptor()), 0, mSize, null);
+ ParcelFileDescriptor.dup(mImage.getFileDescriptor()), 0, mSize, null);
when(mProvider.openTypedAssetFile(any(), any(), any(), any(), any())).thenReturn(
afd);
}
diff --git a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java
index 4a4c693..5a4561d 100644
--- a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java
+++ b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java
@@ -198,7 +198,7 @@
}
@Override
- MainContentCaptureSession getMainCaptureSession() {
+ ContentCaptureSession getMainCaptureSession() {
throw new UnsupportedOperationException("should not have been called");
}
diff --git a/core/tests/coretests/src/android/view/contentcapture/MainContentCaptureSessionTest.java b/core/tests/coretests/src/android/view/contentcapture/MainContentCaptureSessionTest.java
index 1cdcb37..b42bcee 100644
--- a/core/tests/coretests/src/android/view/contentcapture/MainContentCaptureSessionTest.java
+++ b/core/tests/coretests/src/android/view/contentcapture/MainContentCaptureSessionTest.java
@@ -433,6 +433,72 @@
assertThat(session.mEvents).isEmpty();
}
+ @Test
+ public void notifyViewAppearedBelowMaximumBufferSize() throws RemoteException {
+ ContentCaptureOptions options =
+ createOptions(
+ /* enableContentCaptureReceiver= */ true,
+ /* enableContentProtectionReceiver= */ true);
+ MainContentCaptureSession session = createSession(options);
+ session.mDirectServiceInterface = mMockContentCaptureDirectManager;
+
+ session.onSessionStarted(0x2, null);
+ for (int i = 0; i < BUFFER_SIZE - 1; i++) {
+ View view = prepareView(session);
+ session.notifyViewAppeared(session.newViewStructure(view));
+ }
+ mTestableLooper.processAllMessages();
+
+ verify(mMockContentCaptureDirectManager, times(0))
+ .sendEvents(any(), anyInt(), any());
+ assertThat(session.mEvents).isNull();
+ assertThat(session.mEventProcessQueue).hasSize(BUFFER_SIZE - 1);
+ }
+
+ @Test
+ public void notifyViewAppearedExactAsMaximumBufferSize() throws RemoteException {
+ ContentCaptureOptions options =
+ createOptions(
+ /* enableContentCaptureReceiver= */ true,
+ /* enableContentProtectionReceiver= */ true);
+ MainContentCaptureSession session = createSession(options);
+ session.mDirectServiceInterface = mMockContentCaptureDirectManager;
+
+ session.onSessionStarted(0x2, null);
+ for (int i = 0; i < BUFFER_SIZE; i++) {
+ View view = prepareView(session);
+ session.notifyViewAppeared(session.newViewStructure(view));
+ }
+ mTestableLooper.processAllMessages();
+
+ verify(mMockContentCaptureDirectManager, times(1))
+ .sendEvents(any(), anyInt(), any());
+ assertThat(session.mEvents).isEmpty();
+ assertThat(session.mEventProcessQueue).isEmpty();
+ }
+
+ @Test
+ public void notifyViewAppearedAboveMaximumBufferSize() throws RemoteException {
+ ContentCaptureOptions options =
+ createOptions(
+ /* enableContentCaptureReceiver= */ true,
+ /* enableContentProtectionReceiver= */ true);
+ MainContentCaptureSession session = createSession(options);
+ session.mDirectServiceInterface = mMockContentCaptureDirectManager;
+
+ session.onSessionStarted(0x2, null);
+ for (int i = 0; i < BUFFER_SIZE * 2 + 1; i++) {
+ View view = prepareView(session);
+ session.notifyViewAppeared(session.newViewStructure(view));
+ }
+ mTestableLooper.processAllMessages();
+
+ verify(mMockContentCaptureDirectManager, times(2))
+ .sendEvents(any(), anyInt(), any());
+ assertThat(session.mEvents).isEmpty();
+ assertThat(session.mEventProcessQueue).hasSize(1);
+ }
+
/** Simulates the regular content capture events sequence. */
private void notifyContentCaptureEvents(final MainContentCaptureSession session) {
final ArrayList<Object> events = new ArrayList<>(
@@ -489,11 +555,13 @@
}
private MainContentCaptureSession createSession(ContentCaptureManager manager) {
+ final Handler testHandler = Handler.createAsync(mTestableLooper.getLooper());
MainContentCaptureSession session =
new MainContentCaptureSession(
sStrippedContext,
manager,
- Handler.createAsync(mTestableLooper.getLooper()),
+ testHandler,
+ testHandler,
mMockSystemServerInterface);
session.mComponentName = COMPONENT_NAME;
return session;
diff --git a/core/tests/coretests/src/android/view/contentcapture/MainContentCaptureSessionV2Test.java b/core/tests/coretests/src/android/view/contentcapture/MainContentCaptureSessionV2Test.java
deleted file mode 100644
index 0075128..0000000
--- a/core/tests/coretests/src/android/view/contentcapture/MainContentCaptureSessionV2Test.java
+++ /dev/null
@@ -1,596 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.view.contentcapture;
-
-import static android.view.contentcapture.ContentCaptureEvent.TYPE_SESSION_STARTED;
-import static android.view.contentcapture.ContentCaptureSession.FLUSH_REASON_VIEW_TREE_APPEARED;
-import static android.view.contentcapture.ContentCaptureSession.FLUSH_REASON_VIEW_TREE_APPEARING;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.anyInt;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
-
-import android.content.ComponentName;
-import android.content.ContentCaptureOptions;
-import android.content.Context;
-import android.content.pm.ParceledListSlice;
-import android.graphics.Insets;
-import android.os.Handler;
-import android.os.RemoteException;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-import android.util.SparseArray;
-import android.view.View;
-import android.view.autofill.AutofillId;
-import android.view.contentprotection.ContentProtectionEventProcessor;
-
-import androidx.test.core.app.ApplicationProvider;
-import androidx.test.filters.SmallTest;
-
-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.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Test for {@link MainContentCaptureSessionV2}.
- *
- * <p>Run with: {@code atest
- * FrameworksCoreTests:android.view.contentcapture.MainContentCaptureSessionV2Test}
- */
-@RunWith(AndroidTestingRunner.class)
-@SmallTest
-@TestableLooper.RunWithLooper
-public class MainContentCaptureSessionV2Test {
-
- private static final int BUFFER_SIZE = 100;
-
- private static final int REASON = 123;
-
- private static final ContentCaptureEvent EVENT =
- new ContentCaptureEvent(/* sessionId= */ 0, TYPE_SESSION_STARTED);
-
- private static final ComponentName COMPONENT_NAME =
- new ComponentName("com.test.package", "TestClass");
-
- private static final Context sContext = ApplicationProvider.getApplicationContext();
-
- private static final ContentCaptureManager.StrippedContext sStrippedContext =
- new ContentCaptureManager.StrippedContext(sContext);
-
- private TestableLooper mTestableLooper;
-
- @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule();
-
- @Mock private IContentCaptureManager mMockSystemServerInterface;
-
- @Mock private ContentProtectionEventProcessor mMockContentProtectionEventProcessor;
-
- @Mock private IContentCaptureDirectManager mMockContentCaptureDirectManager;
-
- @Before
- public void setup() {
- mTestableLooper = TestableLooper.get(this);
- }
-
- @Test
- public void onSessionStarted_contentProtectionEnabled_processorCreated() {
- MainContentCaptureSessionV2 session = createSession();
- assertThat(session.mContentProtectionEventProcessor).isNull();
-
- session.onSessionStarted(/* resultCode= */ 0, /* binder= */ null);
- mTestableLooper.processAllMessages();
-
- assertThat(session.mContentProtectionEventProcessor).isNotNull();
- }
-
- @Test
- public void onSessionStarted_contentProtectionDisabled_processorNotCreated() {
- MainContentCaptureSessionV2 session =
- createSession(
- /* enableContentCaptureReceiver= */ true,
- /* enableContentProtectionReceiver= */ false);
- session.mContentProtectionEventProcessor = mMockContentProtectionEventProcessor;
-
- session.onSessionStarted(/* resultCode= */ 0, /* binder= */ null);
- mTestableLooper.processAllMessages();
-
- assertThat(session.mContentProtectionEventProcessor).isNull();
- verifyZeroInteractions(mMockContentProtectionEventProcessor);
- }
-
- @Test
- public void onSessionStarted_contentProtectionNoBuffer_processorNotCreated() {
- ContentCaptureOptions options =
- createOptions(
- /* enableContentCaptureReceiver= */ true,
- new ContentCaptureOptions.ContentProtectionOptions(
- /* enableReceiver= */ true,
- -BUFFER_SIZE,
- /* requiredGroups= */ List.of(List.of("a")),
- /* optionalGroups= */ Collections.emptyList(),
- /* optionalGroupsThreshold= */ 0));
- MainContentCaptureSessionV2 session = createSession(options);
- session.mContentProtectionEventProcessor = mMockContentProtectionEventProcessor;
-
- session.onSessionStarted(/* resultCode= */ 0, /* binder= */ null);
- mTestableLooper.processAllMessages();
-
- assertThat(session.mContentProtectionEventProcessor).isNull();
- verifyZeroInteractions(mMockContentProtectionEventProcessor);
- }
-
- @Test
- public void onSessionStarted_contentProtectionNoGroups_processorNotCreated() {
- ContentCaptureOptions options =
- createOptions(
- /* enableContentCaptureReceiver= */ true,
- new ContentCaptureOptions.ContentProtectionOptions(
- /* enableReceiver= */ true,
- BUFFER_SIZE,
- /* requiredGroups= */ Collections.emptyList(),
- /* optionalGroups= */ Collections.emptyList(),
- /* optionalGroupsThreshold= */ 0));
- MainContentCaptureSessionV2 session = createSession(options);
- session.mContentProtectionEventProcessor = mMockContentProtectionEventProcessor;
-
- session.onSessionStarted(/* resultCode= */ 0, /* binder= */ null);
- mTestableLooper.processAllMessages();
-
- assertThat(session.mContentProtectionEventProcessor).isNull();
- verifyZeroInteractions(mMockContentProtectionEventProcessor);
- }
-
- @Test
- public void onSessionStarted_noComponentName_processorNotCreated() {
- MainContentCaptureSessionV2 session = createSession();
- session.mComponentName = null;
-
- session.onSessionStarted(/* resultCode= */ 0, /* binder= */ null);
- mTestableLooper.processAllMessages();
-
- assertThat(session.mContentProtectionEventProcessor).isNull();
- }
-
- @Test
- public void sendEvent_contentCaptureDisabled_contentProtectionDisabled() {
- MainContentCaptureSessionV2 session =
- createSession(
- /* enableContentCaptureReceiver= */ false,
- /* enableContentProtectionReceiver= */ false);
- session.mContentProtectionEventProcessor = mMockContentProtectionEventProcessor;
-
- session.sendEvent(EVENT);
- mTestableLooper.processAllMessages();
-
- verifyZeroInteractions(mMockContentProtectionEventProcessor);
- assertThat(session.mEvents).isNull();
- }
-
- @Test
- public void sendEvent_contentCaptureDisabled_contentProtectionEnabled() {
- MainContentCaptureSessionV2 session =
- createSession(
- /* enableContentCaptureReceiver= */ false,
- /* enableContentProtectionReceiver= */ true);
- session.mContentProtectionEventProcessor = mMockContentProtectionEventProcessor;
-
- session.sendEvent(EVENT);
- mTestableLooper.processAllMessages();
-
- verify(mMockContentProtectionEventProcessor).processEvent(EVENT);
- assertThat(session.mEvents).isNull();
- }
-
- @Test
- public void sendEvent_contentCaptureEnabled_contentProtectionDisabled() {
- MainContentCaptureSessionV2 session =
- createSession(
- /* enableContentCaptureReceiver= */ true,
- /* enableContentProtectionReceiver= */ false);
- session.mContentProtectionEventProcessor = mMockContentProtectionEventProcessor;
-
- session.sendEvent(EVENT);
- mTestableLooper.processAllMessages();
-
- verifyZeroInteractions(mMockContentProtectionEventProcessor);
- assertThat(session.mEvents).isNotNull();
- assertThat(session.mEvents).containsExactly(EVENT);
- }
-
- @Test
- public void sendEvent_contentCaptureEnabled_contentProtectionEnabled() {
- MainContentCaptureSessionV2 session = createSession();
- session.mContentProtectionEventProcessor = mMockContentProtectionEventProcessor;
-
- session.sendEvent(EVENT);
- mTestableLooper.processAllMessages();
-
- verify(mMockContentProtectionEventProcessor).processEvent(EVENT);
- assertThat(session.mEvents).isNotNull();
- assertThat(session.mEvents).containsExactly(EVENT);
- }
-
- @Test
- public void sendEvent_contentProtectionEnabled_processorNotCreated() {
- MainContentCaptureSessionV2 session =
- createSession(
- /* enableContentCaptureReceiver= */ false,
- /* enableContentProtectionReceiver= */ true);
-
- session.sendEvent(EVENT);
- mTestableLooper.processAllMessages();
-
- verifyZeroInteractions(mMockContentProtectionEventProcessor);
- assertThat(session.mEvents).isNull();
- }
-
- @Test
- public void flush_contentCaptureDisabled_contentProtectionDisabled() throws Exception {
- ContentCaptureOptions options =
- createOptions(
- /* enableContentCaptureReceiver= */ false,
- /* enableContentProtectionReceiver= */ false);
- MainContentCaptureSessionV2 session = createSession(options);
- session.mEvents = new ArrayList<>(Arrays.asList(EVENT));
- session.mDirectServiceInterface = mMockContentCaptureDirectManager;
-
- session.flush(REASON);
- mTestableLooper.processAllMessages();
-
- verifyZeroInteractions(mMockContentProtectionEventProcessor);
- verifyZeroInteractions(mMockContentCaptureDirectManager);
- assertThat(session.mEvents).containsExactly(EVENT);
- }
-
- @Test
- public void flush_contentCaptureDisabled_contentProtectionEnabled() {
- MainContentCaptureSessionV2 session =
- createSession(
- /* enableContentCaptureReceiver= */ false,
- /* enableContentProtectionReceiver= */ true);
- session.mEvents = new ArrayList<>(Arrays.asList(EVENT));
- session.mDirectServiceInterface = mMockContentCaptureDirectManager;
-
- session.flush(REASON);
- mTestableLooper.processAllMessages();
-
- verifyZeroInteractions(mMockContentProtectionEventProcessor);
- verifyZeroInteractions(mMockContentCaptureDirectManager);
- assertThat(session.mEvents).containsExactly(EVENT);
- }
-
- @Test
- public void flush_contentCaptureEnabled_contentProtectionDisabled() throws Exception {
- ContentCaptureOptions options =
- createOptions(
- /* enableContentCaptureReceiver= */ true,
- /* enableContentProtectionReceiver= */ false);
- MainContentCaptureSessionV2 session = createSession(options);
- session.mEvents = new ArrayList<>(Arrays.asList(EVENT));
- session.mDirectServiceInterface = mMockContentCaptureDirectManager;
-
- session.flush(REASON);
- mTestableLooper.processAllMessages();
-
- verifyZeroInteractions(mMockContentProtectionEventProcessor);
- assertThat(session.mEvents).isEmpty();
- assertEventFlushedContentCapture(options);
- }
-
- @Test
- public void flush_contentCaptureEnabled_contentProtectionEnabled() throws Exception {
- ContentCaptureOptions options =
- createOptions(
- /* enableContentCaptureReceiver= */ true,
- /* enableContentProtectionReceiver= */ true);
- MainContentCaptureSessionV2 session = createSession(options);
- session.mEvents = new ArrayList<>(Arrays.asList(EVENT));
- session.mDirectServiceInterface = mMockContentCaptureDirectManager;
-
- session.flush(REASON);
- mTestableLooper.processAllMessages();
-
- verifyZeroInteractions(mMockContentProtectionEventProcessor);
- assertThat(session.mEvents).isEmpty();
- assertEventFlushedContentCapture(options);
- }
-
- @Test
- public void destroySession() throws Exception {
- MainContentCaptureSessionV2 session = createSession();
- session.mContentProtectionEventProcessor = mMockContentProtectionEventProcessor;
-
- session.destroySession();
- mTestableLooper.processAllMessages();
-
- verify(mMockSystemServerInterface).finishSession(anyInt());
- verifyZeroInteractions(mMockContentProtectionEventProcessor);
- assertThat(session.mDirectServiceInterface).isNull();
- assertThat(session.mContentProtectionEventProcessor).isNull();
- }
-
- @Test
- public void resetSession() {
- MainContentCaptureSessionV2 session = createSession();
- session.mContentProtectionEventProcessor = mMockContentProtectionEventProcessor;
-
- session.resetSession(/* newState= */ 0);
- mTestableLooper.processAllMessages();
-
- verifyZeroInteractions(mMockSystemServerInterface);
- verifyZeroInteractions(mMockContentProtectionEventProcessor);
- assertThat(session.mDirectServiceInterface).isNull();
- assertThat(session.mContentProtectionEventProcessor).isNull();
- }
-
- @Test
- @SuppressWarnings("GuardedBy")
- public void notifyContentCaptureEvents_notStarted_ContentCaptureDisabled_ProtectionDisabled() {
- ContentCaptureOptions options =
- createOptions(
- /* enableContentCaptureReceiver= */ false,
- /* enableContentProtectionReceiver= */ false);
- MainContentCaptureSessionV2 session = createSession(options);
-
- notifyContentCaptureEvents(session);
- mTestableLooper.processAllMessages();
-
- verifyZeroInteractions(mMockContentCaptureDirectManager);
- verifyZeroInteractions(mMockContentProtectionEventProcessor);
- assertThat(session.mEvents).isNull();
- }
-
- @Test
- @SuppressWarnings("GuardedBy")
- public void notifyContentCaptureEvents_started_ContentCaptureDisabled_ProtectionDisabled() {
- ContentCaptureOptions options =
- createOptions(
- /* enableContentCaptureReceiver= */ false,
- /* enableContentProtectionReceiver= */ false);
- MainContentCaptureSessionV2 session = createSession(options);
-
- session.onSessionStarted(0x2, null);
- notifyContentCaptureEvents(session);
- mTestableLooper.processAllMessages();
-
- verifyZeroInteractions(mMockContentCaptureDirectManager);
- verifyZeroInteractions(mMockContentProtectionEventProcessor);
- assertThat(session.mEvents).isNull();
- }
-
- @Test
- @SuppressWarnings("GuardedBy")
- public void notifyContentCaptureEvents_notStarted_ContentCaptureEnabled_ProtectionEnabled() {
- ContentCaptureOptions options =
- createOptions(
- /* enableContentCaptureReceiver= */ true,
- /* enableContentProtectionReceiver= */ true);
- MainContentCaptureSessionV2 session = createSession(options);
- session.mDirectServiceInterface = mMockContentCaptureDirectManager;
- session.mContentProtectionEventProcessor = mMockContentProtectionEventProcessor;
-
- notifyContentCaptureEvents(session);
- mTestableLooper.processAllMessages();
-
- verifyZeroInteractions(mMockContentCaptureDirectManager);
- verifyZeroInteractions(mMockContentProtectionEventProcessor);
- assertThat(session.mEvents).isNull();
- }
-
- @Test
- @SuppressWarnings("GuardedBy")
- public void notifyContentCaptureEvents_started_ContentCaptureEnabled_ProtectionEnabled()
- throws RemoteException {
- ContentCaptureOptions options =
- createOptions(
- /* enableContentCaptureReceiver= */ true,
- /* enableContentProtectionReceiver= */ true);
- MainContentCaptureSessionV2 session = createSession(options);
- session.mDirectServiceInterface = mMockContentCaptureDirectManager;
-
- session.onSessionStarted(0x2, null);
- // Override the processor for interaction verification.
- session.mContentProtectionEventProcessor = mMockContentProtectionEventProcessor;
- notifyContentCaptureEvents(session);
- mTestableLooper.processAllMessages();
-
- // Force flush will happen twice.
- verify(mMockContentCaptureDirectManager, times(1))
- .sendEvents(any(), eq(FLUSH_REASON_VIEW_TREE_APPEARING), any());
- verify(mMockContentCaptureDirectManager, times(1))
- .sendEvents(any(), eq(FLUSH_REASON_VIEW_TREE_APPEARED), any());
- // Other than the five view events, there will be two additional tree appearing events.
- verify(mMockContentProtectionEventProcessor, times(7)).processEvent(any());
- assertThat(session.mEvents).isEmpty();
- }
-
- @Test
- public void notifyViewAppearedBelowMaximumBufferSize() throws RemoteException {
- ContentCaptureOptions options =
- createOptions(
- /* enableContentCaptureReceiver= */ true,
- /* enableContentProtectionReceiver= */ true);
- MainContentCaptureSessionV2 session = createSession(options);
- session.mDirectServiceInterface = mMockContentCaptureDirectManager;
-
- session.onSessionStarted(0x2, null);
- for (int i = 0; i < BUFFER_SIZE - 1; i++) {
- View view = prepareView(session);
- session.notifyViewAppeared(session.newViewStructure(view));
- }
- mTestableLooper.processAllMessages();
-
- verify(mMockContentCaptureDirectManager, times(0))
- .sendEvents(any(), anyInt(), any());
- assertThat(session.mEvents).isNull();
- assertThat(session.mEventProcessQueue).hasSize(BUFFER_SIZE - 1);
- }
-
- @Test
- public void notifyViewAppearedExactAsMaximumBufferSize() throws RemoteException {
- ContentCaptureOptions options =
- createOptions(
- /* enableContentCaptureReceiver= */ true,
- /* enableContentProtectionReceiver= */ true);
- MainContentCaptureSessionV2 session = createSession(options);
- session.mDirectServiceInterface = mMockContentCaptureDirectManager;
-
- session.onSessionStarted(0x2, null);
- for (int i = 0; i < BUFFER_SIZE; i++) {
- View view = prepareView(session);
- session.notifyViewAppeared(session.newViewStructure(view));
- }
- mTestableLooper.processAllMessages();
-
- verify(mMockContentCaptureDirectManager, times(1))
- .sendEvents(any(), anyInt(), any());
- assertThat(session.mEvents).isEmpty();
- assertThat(session.mEventProcessQueue).isEmpty();
- }
-
- @Test
- public void notifyViewAppearedAboveMaximumBufferSize() throws RemoteException {
- ContentCaptureOptions options =
- createOptions(
- /* enableContentCaptureReceiver= */ true,
- /* enableContentProtectionReceiver= */ true);
- MainContentCaptureSessionV2 session = createSession(options);
- session.mDirectServiceInterface = mMockContentCaptureDirectManager;
-
- session.onSessionStarted(0x2, null);
- for (int i = 0; i < BUFFER_SIZE * 2 + 1; i++) {
- View view = prepareView(session);
- session.notifyViewAppeared(session.newViewStructure(view));
- }
- mTestableLooper.processAllMessages();
-
- verify(mMockContentCaptureDirectManager, times(2))
- .sendEvents(any(), anyInt(), any());
- assertThat(session.mEvents).isEmpty();
- assertThat(session.mEventProcessQueue).hasSize(1);
- }
-
- /** Simulates the regular content capture events sequence. */
- private void notifyContentCaptureEvents(final MainContentCaptureSessionV2 session) {
- final ArrayList<Object> events = new ArrayList<>(
- List.of(
- prepareView(session),
- prepareView(session),
- new AutofillId(0),
- prepareView(session),
- Insets.of(0, 0, 0, 0)
- )
- );
-
- final SparseArray<ArrayList<Object>> contentCaptureEvents = new SparseArray<>();
- contentCaptureEvents.set(session.getId(), events);
-
- session.notifyContentCaptureEvents(contentCaptureEvents);
- }
-
- private View prepareView(final MainContentCaptureSessionV2 session) {
- final View view = new View(sContext);
- view.setContentCaptureSession(session);
- return view;
- }
-
- private static ContentCaptureOptions createOptions(
- boolean enableContentCaptureReceiver,
- ContentCaptureOptions.ContentProtectionOptions contentProtectionOptions) {
- return new ContentCaptureOptions(
- /* loggingLevel= */ 0,
- BUFFER_SIZE,
- /* idleFlushingFrequencyMs= */ 0,
- /* textChangeFlushingFrequencyMs= */ 0,
- /* logHistorySize= */ 0,
- /* disableFlushForViewTreeAppearing= */ false,
- enableContentCaptureReceiver,
- contentProtectionOptions,
- /* whitelistedComponents= */ null);
- }
-
- private static ContentCaptureOptions createOptions(
- boolean enableContentCaptureReceiver, boolean enableContentProtectionReceiver) {
- return createOptions(
- enableContentCaptureReceiver,
- new ContentCaptureOptions.ContentProtectionOptions(
- enableContentProtectionReceiver,
- BUFFER_SIZE,
- /* requiredGroups= */ List.of(List.of("a")),
- /* optionalGroups= */ Collections.emptyList(),
- /* optionalGroupsThreshold= */ 0));
- }
-
- private ContentCaptureManager createManager(ContentCaptureOptions options) {
- return new ContentCaptureManager(sContext, mMockSystemServerInterface, options);
- }
-
- private MainContentCaptureSessionV2 createSession(ContentCaptureManager manager) {
- final Handler testHandler = Handler.createAsync(mTestableLooper.getLooper());
- MainContentCaptureSessionV2 session =
- new MainContentCaptureSessionV2(
- sStrippedContext,
- manager,
- testHandler,
- testHandler,
- mMockSystemServerInterface);
- session.mComponentName = COMPONENT_NAME;
- return session;
- }
-
- private MainContentCaptureSessionV2 createSession(ContentCaptureOptions options) {
- return createSession(createManager(options));
- }
-
- private MainContentCaptureSessionV2 createSession(
- boolean enableContentCaptureReceiver, boolean enableContentProtectionReceiver) {
- return createSession(
- createOptions(enableContentCaptureReceiver, enableContentProtectionReceiver));
- }
-
- private MainContentCaptureSessionV2 createSession() {
- return createSession(
- /* enableContentCaptureReceiver= */ true,
- /* enableContentProtectionReceiver= */ true);
- }
-
- private void assertEventFlushedContentCapture(ContentCaptureOptions options) throws Exception {
- ArgumentCaptor<ParceledListSlice> captor = ArgumentCaptor.forClass(ParceledListSlice.class);
- verify(mMockContentCaptureDirectManager)
- .sendEvents(captor.capture(), eq(REASON), eq(options));
-
- assertThat(captor.getValue()).isNotNull();
- List<ContentCaptureEvent> actual = captor.getValue().getList();
- assertThat(actual).isNotNull();
- assertThat(actual).containsExactly(EVENT);
- }
-}
diff --git a/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java b/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
index b0190a5..d4482f2 100644
--- a/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
+++ b/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
@@ -112,7 +112,7 @@
doReturn(mApplicationInfo).when(mContext).getApplicationInfo();
mDispatcher = new WindowOnBackInvokedDispatcher(mContext, Looper.getMainLooper());
- mDispatcher.attachToWindow(mWindowSession, mWindow, mImeBackAnimationController);
+ mDispatcher.attachToWindow(mWindowSession, mWindow, null, mImeBackAnimationController);
}
private void waitForIdle() {
@@ -455,25 +455,26 @@
@Test
public void registerImeCallbacks_onBackInvokedCallbackEnabled() throws RemoteException {
- mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mDefaultImeCallback);
+ verifyImeCallackRegistrations();
+ }
+
+ @Test
+ public void registerImeCallbacks_onBackInvokedCallbackDisabled() throws RemoteException {
+ doReturn(false).when(mApplicationInfo).isOnBackInvokedCallbackEnabled();
+ verifyImeCallackRegistrations();
+ }
+
+ private void verifyImeCallackRegistrations() throws RemoteException {
+ // verify default callback is replaced with ImeBackAnimationController
+ mDispatcher.registerOnBackInvokedCallbackUnchecked(mDefaultImeCallback, PRIORITY_DEFAULT);
assertCallbacksSize(/* default */ 1, /* overlay */ 0);
assertSetCallbackInfo();
assertTopCallback(mImeBackAnimationController);
- mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mImeCallback);
+ // verify regular ime callback is successfully registered
+ mDispatcher.registerOnBackInvokedCallbackUnchecked(mImeCallback, PRIORITY_DEFAULT);
assertCallbacksSize(/* default */ 2, /* overlay */ 0);
assertSetCallbackInfo();
assertTopCallback(mImeCallback);
}
-
- @Test
- public void registerImeCallbacks_legacyBack() throws RemoteException {
- doReturn(false).when(mApplicationInfo).isOnBackInvokedCallbackEnabled();
-
- mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mDefaultImeCallback);
- assertNoSetCallbackInfo();
-
- mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mImeCallback);
- assertNoSetCallbackInfo();
- }
}
diff --git a/core/tests/coretests/src/com/android/internal/accessibility/util/ShortcutUtilsTest.java b/core/tests/coretests/src/com/android/internal/accessibility/util/ShortcutUtilsTest.java
index 708f246..928fce9 100644
--- a/core/tests/coretests/src/com/android/internal/accessibility/util/ShortcutUtilsTest.java
+++ b/core/tests/coretests/src/com/android/internal/accessibility/util/ShortcutUtilsTest.java
@@ -25,33 +25,28 @@
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.accessibilityservice.AccessibilityServiceInfo;
+import android.annotation.UserIdInt;
import android.content.ComponentName;
-import android.content.ContentResolver;
import android.content.Context;
-import android.content.ContextWrapper;
import android.content.pm.ParceledListSlice;
import android.os.Handler;
import android.os.RemoteException;
-import android.os.UserHandle;
import android.provider.Settings;
+import android.testing.TestableContext;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.IAccessibilityManager;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.platform.app.InstrumentationRegistry;
-import androidx.test.runner.AndroidJUnit4;
import com.android.internal.accessibility.AccessibilityShortcutController;
import com.android.internal.accessibility.TestUtils;
import com.android.internal.accessibility.common.ShortcutConstants;
-import com.android.internal.util.test.FakeSettingsProvider;
-import com.android.internal.util.test.FakeSettingsProviderRule;
import org.junit.Before;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -79,39 +74,33 @@
private static final String STANDARD_SERVICE_COMPONENT_NAME =
"fake.package/fake.standard.service.name";
private static final String SERVICE_NAME_SUMMARY = "Summary";
-
- @Rule
- public FakeSettingsProviderRule mSettingsProviderRule = FakeSettingsProvider.rule();
@Mock
private IAccessibilityManager mAccessibilityManagerService;
- private ContextWrapper mContextSpy;
+ private TestableContext mContext;
+ @UserIdInt
+ private int mDefaultUserId;
@Before
public void setUp() throws RemoteException {
MockitoAnnotations.initMocks(this);
- mContextSpy = spy(
- new ContextWrapper(InstrumentationRegistry.getInstrumentation().getContext()));
-
- ContentResolver contentResolver = mSettingsProviderRule.mockContentResolver(mContextSpy);
- when(mContextSpy.getContentResolver()).thenReturn(contentResolver);
+ mContext = new TestableContext(InstrumentationRegistry.getInstrumentation().getContext());
+ mDefaultUserId = mContext.getContentResolver().getUserId();
AccessibilityManager accessibilityManager =
new AccessibilityManager(
- mContextSpy, mock(Handler.class),
- mAccessibilityManagerService, UserHandle.myUserId(),
+ mContext, mock(Handler.class),
+ mAccessibilityManagerService, mDefaultUserId,
/* serviceConnect= */ true);
- when(mContextSpy.getSystemService(Context.ACCESSIBILITY_SERVICE))
- .thenReturn(accessibilityManager);
-
- setupFakeA11yServiceInfos();
+ mContext.addMockSystemService(Context.ACCESSIBILITY_SERVICE, accessibilityManager);
+ setupFakeInstalledA11yServiceInfos();
}
@Test
public void getShortcutTargets_softwareShortcutNoService_emptyResult() {
assertThat(
ShortcutUtils.getShortcutTargetsFromSettings(
- mContextSpy,
- ShortcutConstants.UserShortcutType.SOFTWARE, UserHandle.myUserId())
+ mContext,
+ ShortcutConstants.UserShortcutType.SOFTWARE, mDefaultUserId)
).isEmpty();
}
@@ -119,8 +108,8 @@
public void getShortcutTargets_volumeKeyShortcutNoService_emptyResult() {
assertThat(
ShortcutUtils.getShortcutTargetsFromSettings(
- mContextSpy, ShortcutConstants.UserShortcutType.HARDWARE,
- UserHandle.myUserId())
+ mContext, ShortcutConstants.UserShortcutType.HARDWARE,
+ mDefaultUserId)
).isEmpty();
}
@@ -131,8 +120,8 @@
assertThat(
ShortcutUtils.getShortcutTargetsFromSettings(
- mContextSpy, ShortcutConstants.UserShortcutType.SOFTWARE,
- UserHandle.myUserId())
+ mContext, ShortcutConstants.UserShortcutType.SOFTWARE,
+ mDefaultUserId)
).containsExactlyElementsIn(ONE_COMPONENT);
}
@@ -143,8 +132,8 @@
assertThat(
ShortcutUtils.getShortcutTargetsFromSettings(
- mContextSpy, ShortcutConstants.UserShortcutType.HARDWARE,
- UserHandle.myUserId())
+ mContext, ShortcutConstants.UserShortcutType.HARDWARE,
+ mDefaultUserId)
).containsExactlyElementsIn(TWO_COMPONENTS);
}
@@ -156,8 +145,8 @@
assertThat(
ShortcutUtils.getShortcutTargetsFromSettings(
- mContextSpy, ShortcutConstants.UserShortcutType.TRIPLETAP,
- UserHandle.myUserId())
+ mContext, ShortcutConstants.UserShortcutType.TRIPLETAP,
+ mDefaultUserId)
).isEmpty();
}
@@ -169,8 +158,8 @@
assertThat(
ShortcutUtils.getShortcutTargetsFromSettings(
- mContextSpy, ShortcutConstants.UserShortcutType.TRIPLETAP,
- UserHandle.myUserId())
+ mContext, ShortcutConstants.UserShortcutType.TRIPLETAP,
+ mDefaultUserId)
).containsExactly(ACCESSIBILITY_SHORTCUT_TARGET_MAGNIFICATION_CONTROLLER);
}
@@ -180,23 +169,46 @@
ALWAYS_ON_SERVICE_COMPONENT_NAME, /* serviceOn= */ true, /* shortcutOn= */ false);
ShortcutUtils.updateInvisibleToggleAccessibilityServiceEnableState(
- mContextSpy,
+ mContext,
Set.of(ALWAYS_ON_SERVICE_COMPONENT_NAME),
- UserHandle.myUserId()
+ mDefaultUserId
);
assertA11yServiceState(ALWAYS_ON_SERVICE_COMPONENT_NAME, /* enabled= */ false);
}
@Test
+ public void updateAccessibilityServiceStateIfNeeded_alwaysOnServiceOnForBothUsers_noShortcutsForGuestUser_serviceTurnedOffForGuestUserOnly() {
+ // setup arbitrary userId by add 10 to the default user id
+ final int guestUserId = mDefaultUserId + 10;
+ setupA11yServiceAndShortcutStateForUser(
+ ALWAYS_ON_SERVICE_COMPONENT_NAME, /* serviceOn= */ true,
+ /* shortcutOn= */ true, mDefaultUserId);
+ setupA11yServiceAndShortcutStateForUser(
+ ALWAYS_ON_SERVICE_COMPONENT_NAME, /* serviceOn= */ true,
+ /* shortcutOn= */ false, guestUserId);
+
+ ShortcutUtils.updateInvisibleToggleAccessibilityServiceEnableState(
+ mContext,
+ Set.of(ALWAYS_ON_SERVICE_COMPONENT_NAME),
+ guestUserId
+ );
+
+ assertA11yServiceStateForUser(
+ ALWAYS_ON_SERVICE_COMPONENT_NAME, /* enabled= */ false, guestUserId);
+ assertA11yServiceStateForUser(
+ ALWAYS_ON_SERVICE_COMPONENT_NAME, /* enabled= */ true, mDefaultUserId);
+ }
+
+ @Test
public void updateAccessibilityServiceStateIfNeeded_alwaysOnServiceOn_hasShortcut_serviceKeepsOn() {
setupA11yServiceAndShortcutState(
ALWAYS_ON_SERVICE_COMPONENT_NAME, /* serviceOn= */ true, /* shortcutOn= */ true);
ShortcutUtils.updateInvisibleToggleAccessibilityServiceEnableState(
- mContextSpy,
+ mContext,
Set.of(ALWAYS_ON_SERVICE_COMPONENT_NAME),
- UserHandle.myUserId()
+ mDefaultUserId
);
assertA11yServiceState(ALWAYS_ON_SERVICE_COMPONENT_NAME, /* enabled= */ true);
@@ -208,9 +220,9 @@
ALWAYS_ON_SERVICE_COMPONENT_NAME, /* serviceOn= */ false, /* shortcutOn= */ false);
ShortcutUtils.updateInvisibleToggleAccessibilityServiceEnableState(
- mContextSpy,
+ mContext,
Set.of(ALWAYS_ON_SERVICE_COMPONENT_NAME),
- UserHandle.myUserId()
+ mDefaultUserId
);
assertA11yServiceState(ALWAYS_ON_SERVICE_COMPONENT_NAME, /* enabled= */ false);
@@ -222,9 +234,9 @@
ALWAYS_ON_SERVICE_COMPONENT_NAME, /* serviceOn= */ false, /* shortcutOn= */ true);
ShortcutUtils.updateInvisibleToggleAccessibilityServiceEnableState(
- mContextSpy,
+ mContext,
Set.of(ALWAYS_ON_SERVICE_COMPONENT_NAME),
- UserHandle.myUserId()
+ mDefaultUserId
);
assertA11yServiceState(ALWAYS_ON_SERVICE_COMPONENT_NAME, /* enabled= */ true);
@@ -236,9 +248,9 @@
STANDARD_SERVICE_COMPONENT_NAME, /* serviceOn= */ true, /* shortcutOn= */ false);
ShortcutUtils.updateInvisibleToggleAccessibilityServiceEnableState(
- mContextSpy,
+ mContext,
Set.of(STANDARD_SERVICE_COMPONENT_NAME),
- UserHandle.myUserId()
+ mDefaultUserId
);
assertA11yServiceState(STANDARD_SERVICE_COMPONENT_NAME, /* enabled= */ true);
@@ -250,9 +262,9 @@
STANDARD_SERVICE_COMPONENT_NAME, /* serviceOn= */ true, /* shortcutOn= */ true);
ShortcutUtils.updateInvisibleToggleAccessibilityServiceEnableState(
- mContextSpy,
+ mContext,
Set.of(STANDARD_SERVICE_COMPONENT_NAME),
- UserHandle.myUserId()
+ mDefaultUserId
);
assertA11yServiceState(STANDARD_SERVICE_COMPONENT_NAME, /* enabled= */ true);
@@ -264,9 +276,9 @@
STANDARD_SERVICE_COMPONENT_NAME, /* serviceOn= */ false, /* shortcutOn= */ false);
ShortcutUtils.updateInvisibleToggleAccessibilityServiceEnableState(
- mContextSpy,
+ mContext,
Set.of(STANDARD_SERVICE_COMPONENT_NAME),
- UserHandle.myUserId()
+ mDefaultUserId
);
assertA11yServiceState(STANDARD_SERVICE_COMPONENT_NAME, /* enabled= */ false);
@@ -278,9 +290,9 @@
STANDARD_SERVICE_COMPONENT_NAME, /* serviceOn= */ false, /* shortcutOn= */ true);
ShortcutUtils.updateInvisibleToggleAccessibilityServiceEnableState(
- mContextSpy,
+ mContext,
Set.of(STANDARD_SERVICE_COMPONENT_NAME),
- UserHandle.myUserId()
+ mDefaultUserId
);
assertA11yServiceState(STANDARD_SERVICE_COMPONENT_NAME, /* enabled= */ false);
@@ -292,18 +304,18 @@
stringJoiner.add(target);
}
Settings.Secure.putStringForUser(
- mContextSpy.getContentResolver(), shortcutSettingsKey,
+ mContext.getContentResolver(), shortcutSettingsKey,
stringJoiner.toString(),
- UserHandle.myUserId());
+ mDefaultUserId);
}
private void enableTripleTapShortcutForMagnification(boolean enable) {
Settings.Secure.putInt(
- mContextSpy.getContentResolver(),
+ mContext.getContentResolver(),
ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, enable ? 1 : 0);
}
- private void setupFakeA11yServiceInfos() throws RemoteException {
+ private void setupFakeInstalledA11yServiceInfos() throws RemoteException {
List<AccessibilityServiceInfo> serviceInfos = List.of(
TestUtils.createFakeServiceInfo(
ALWAYS_ON_SERVICE_PACKAGE_LABEL,
@@ -322,37 +334,55 @@
private void setupA11yServiceAndShortcutState(
String a11yServiceComponentName, boolean serviceOn, boolean shortcutOn) {
- enableA11yService(a11yServiceComponentName, serviceOn);
- addShortcutForA11yService(a11yServiceComponentName, shortcutOn);
+ setupA11yServiceAndShortcutStateForUser(
+ a11yServiceComponentName, serviceOn, shortcutOn, mDefaultUserId);
+ }
+
+ private void setupA11yServiceAndShortcutStateForUser(
+ String a11yServiceComponentName, boolean serviceOn,
+ boolean shortcutOn, @UserIdInt int userId) {
+ enableA11yServiceForUser(a11yServiceComponentName, serviceOn, userId);
+ addShortcutForA11yServiceForUser(a11yServiceComponentName, shortcutOn, userId);
}
private void assertA11yServiceState(String a11yServiceComponentName, boolean enabled) {
+ assertA11yServiceStateForUser(a11yServiceComponentName, enabled, mDefaultUserId);
+ }
+
+ private void assertA11yServiceStateForUser(
+ String a11yServiceComponentName, boolean enabled, @UserIdInt int userId) {
if (enabled) {
assertThat(
- Settings.Secure.getString(
- mContextSpy.getContentResolver(),
- Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES)
+ Settings.Secure.getStringForUser(
+ mContext.getContentResolver(),
+ Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
+ userId)
).contains(a11yServiceComponentName);
} else {
assertThat(
- Settings.Secure.getString(
- mContextSpy.getContentResolver(),
- Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES)
+ Settings.Secure.getStringForUser(
+ mContext.getContentResolver(),
+ Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
+ userId)
).doesNotContain(a11yServiceComponentName);
}
}
- private void enableA11yService(String a11yServiceComponentName, boolean enable) {
- Settings.Secure.putString(
- mContextSpy.getContentResolver(),
+ private void enableA11yServiceForUser(
+ String a11yServiceComponentName, boolean enable, @UserIdInt int userId) {
+ Settings.Secure.putStringForUser(
+ mContext.getContentResolver(),
Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
- enable ? a11yServiceComponentName : "");
+ enable ? a11yServiceComponentName : "",
+ userId);
}
- private void addShortcutForA11yService(String a11yServiceComponentName, boolean add) {
- Settings.Secure.putString(
- mContextSpy.getContentResolver(),
+ private void addShortcutForA11yServiceForUser(
+ String a11yServiceComponentName, boolean add, @UserIdInt int userId) {
+ Settings.Secure.putStringForUser(
+ mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
- add ? a11yServiceComponentName : "");
+ add ? a11yServiceComponentName : "",
+ userId);
}
}
diff --git a/libs/WindowManager/Shell/res/values-af/strings.xml b/libs/WindowManager/Shell/res/values-af/strings.xml
index 1c8f5e6..8b328e2 100644
--- a/libs/WindowManager/Shell/res/values-af/strings.xml
+++ b/libs/WindowManager/Shell/res/values-af/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Borrel"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Bestuur"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Borrel is toegemaak."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"Tik om hierdie app te herbegin vir ’n beter aansig"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Verander hierdie app se aspekverhouding in Instellings"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Verander aspekverhouding"</string>
diff --git a/libs/WindowManager/Shell/res/values-am/strings.xml b/libs/WindowManager/Shell/res/values-am/strings.xml
index 81ab3ab..b005a01 100644
--- a/libs/WindowManager/Shell/res/values-am/strings.xml
+++ b/libs/WindowManager/Shell/res/values-am/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"አረፋ"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"ያቀናብሩ"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"አረፋ ተሰናብቷል።"</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"ለተሻለ ዕይታ ይህን መተግበሪያ እንደገና ለመጀመር መታ ያድርጉ"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"የዚህን መተግበሪያ ምጥጥነ ገፅታ በቅንብሮች ውስጥ ይለውጡ"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"የምጥጥነ ገፅታ ለውጥ"</string>
diff --git a/libs/WindowManager/Shell/res/values-ar/strings.xml b/libs/WindowManager/Shell/res/values-ar/strings.xml
index 3974c39..8c283d3 100644
--- a/libs/WindowManager/Shell/res/values-ar/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ar/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"فقاعة"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"إدارة"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"تم إغلاق الفقاعة."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"انقر لإعادة تشغيل هذا التطبيق للحصول على تجربة عرض أفضل."</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"يمكنك تغيير نسبة العرض إلى الارتفاع لهذا التطبيق من خلال \"الإعدادات\"."</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"تغيير نسبة العرض إلى الارتفاع"</string>
diff --git a/libs/WindowManager/Shell/res/values-as/strings.xml b/libs/WindowManager/Shell/res/values-as/strings.xml
index a1ce1b3..ef92587 100644
--- a/libs/WindowManager/Shell/res/values-as/strings.xml
+++ b/libs/WindowManager/Shell/res/values-as/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"বাবল"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"পৰিচালনা কৰক"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"বাবল অগ্ৰাহ্য কৰা হৈছে"</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"উন্নত ভিউ পোৱাৰ বাবে এপ্টো ৰিষ্টাৰ্ট কৰিবলৈ টিপক"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"ছেটিঙলৈ গৈ এই এপ্টোৰ আকাৰৰ অনুপাত সলনি কৰক"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"আকাৰৰ অনুপাত সলনি কৰক"</string>
diff --git a/libs/WindowManager/Shell/res/values-az/strings.xml b/libs/WindowManager/Shell/res/values-az/strings.xml
index 71dfe5a..04b2f1c 100644
--- a/libs/WindowManager/Shell/res/values-az/strings.xml
+++ b/libs/WindowManager/Shell/res/values-az/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Qabarcıq"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"İdarə edin"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Qabarcıqdan imtina edilib."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"Yaxşı görünüş üçün toxunaraq bu tətbiqi yenidən başladın"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Ayarlarda bu tətbiqin tərəflər nisbətini dəyişin"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Tərəflər nisbətini dəyişin"</string>
diff --git a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
index f483609..47bc105 100644
--- a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Oblačić"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Upravljajte"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Oblačić je odbačen."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"Dodirnite da biste restartovali ovu aplikaciju radi boljeg prikaza"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Promenite razmeru ove aplikacije u Podešavanjima"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Promeni razmeru"</string>
diff --git a/libs/WindowManager/Shell/res/values-be/strings.xml b/libs/WindowManager/Shell/res/values-be/strings.xml
index 532ecc6..6ad7553 100644
--- a/libs/WindowManager/Shell/res/values-be/strings.xml
+++ b/libs/WindowManager/Shell/res/values-be/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Усплывальнае апавяшчэнне"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Кіраваць"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Усплывальнае апавяшчэнне адхілена."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"Націсніце, каб перазапусціць гэту праграму для зручнейшага прагляду"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Змяніць суадносіны бакоў для гэтай праграмы ў наладах"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Змяніць суадносіны бакоў"</string>
diff --git a/libs/WindowManager/Shell/res/values-bg/strings.xml b/libs/WindowManager/Shell/res/values-bg/strings.xml
index 8f828ba..a9e0bce 100644
--- a/libs/WindowManager/Shell/res/values-bg/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bg/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Балонче"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Управление"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Балончето е отхвърлено."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"Докоснете, за да рестартирате това приложение с цел по-добър изглед"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Променете съотношението на това приложение в „Настройки“"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Промяна на съотношението"</string>
diff --git a/libs/WindowManager/Shell/res/values-bn/strings.xml b/libs/WindowManager/Shell/res/values-bn/strings.xml
index e0a2ea8..29de100 100644
--- a/libs/WindowManager/Shell/res/values-bn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bn/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"বাবল"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"ম্যানেজ করুন"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"বাবল বাতিল করা হয়েছে।"</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"আরও ভাল ভিউয়ের জন্য এই অ্যাপ রিস্টার্ট করতে ট্যাপ করুন"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"সেটিংস থেকে এই অ্যাপের অ্যাস্পেক্ট রেশিও পরিবর্তন করুন"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"অ্যাস্পেক্ট রেশিও পরিবর্তন করুন"</string>
diff --git a/libs/WindowManager/Shell/res/values-bs/strings.xml b/libs/WindowManager/Shell/res/values-bs/strings.xml
index 41c72c1..5f1da75 100644
--- a/libs/WindowManager/Shell/res/values-bs/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bs/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Oblačić"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Upravljaj"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Oblačić je odbačen."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"Dodirnite da ponovo pokrenete ovu aplikaciju radi boljeg prikaza"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Promijenite format slike aplikacije u Postavkama"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Promijenite format slike"</string>
diff --git a/libs/WindowManager/Shell/res/values-ca/strings.xml b/libs/WindowManager/Shell/res/values-ca/strings.xml
index 6792272..d70de79 100644
--- a/libs/WindowManager/Shell/res/values-ca/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ca/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Bombolla"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Gestiona"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"La bombolla s\'ha ignorat."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"Toca per reiniciar aquesta aplicació i obtenir una millor visualització"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Canvia la relació d\'aspecte d\'aquesta aplicació a Configuració"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Canvia la relació d\'aspecte"</string>
diff --git a/libs/WindowManager/Shell/res/values-cs/strings.xml b/libs/WindowManager/Shell/res/values-cs/strings.xml
index 150a6e6..ca00fec 100644
--- a/libs/WindowManager/Shell/res/values-cs/strings.xml
+++ b/libs/WindowManager/Shell/res/values-cs/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Bublina"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Spravovat"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bublina byla zavřena."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"Klepnutím tuto aplikaci restartujete kvůli lepšímu zobrazení"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Změnit v Nastavení poměr stran této aplikace"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Změnit poměr stran"</string>
diff --git a/libs/WindowManager/Shell/res/values-da/strings.xml b/libs/WindowManager/Shell/res/values-da/strings.xml
index 8878910..d50d2f0 100644
--- a/libs/WindowManager/Shell/res/values-da/strings.xml
+++ b/libs/WindowManager/Shell/res/values-da/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Boble"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Administrer"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Boblen blev lukket."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"Tryk for at genstarte denne app, så visningen forbedres"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Skift denne apps billedformat i Indstillinger"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Skift billedformat"</string>
diff --git a/libs/WindowManager/Shell/res/values-de/strings.xml b/libs/WindowManager/Shell/res/values-de/strings.xml
index 7b91559..7f44f83 100644
--- a/libs/WindowManager/Shell/res/values-de/strings.xml
+++ b/libs/WindowManager/Shell/res/values-de/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Bubble"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Verwalten"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bubble verworfen."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"Tippen, um diese App neu zu starten und die Ansicht zu verbessern"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Seitenverhältnis der App in den Einstellungen ändern"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Seitenverhältnis ändern"</string>
diff --git a/libs/WindowManager/Shell/res/values-el/strings.xml b/libs/WindowManager/Shell/res/values-el/strings.xml
index 14e5e2f..a3a5ccd 100644
--- a/libs/WindowManager/Shell/res/values-el/strings.xml
+++ b/libs/WindowManager/Shell/res/values-el/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Συννεφάκι"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Διαχείριση"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Το συννεφάκι παραβλέφθηκε."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"Πατήστε για να επανεκκινήσετε αυτή την εφαρμογή για καλύτερη προβολή"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Αλλάξτε τον λόγο διαστάσεων αυτής της εφαρμογής στις Ρυθμίσεις"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Αλλαγή λόγου διαστάσεων"</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
index 7427b62..edc4f4e 100644
--- a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Bubble"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Manage"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bubble dismissed."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"Tap to restart this app for a better view"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Change this app\'s aspect ratio in Settings"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Change aspect ratio"</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
index cb9ee4f..e537f0a 100644
--- a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Bubble"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Manage"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bubble dismissed."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"Tap to restart this app for a better view"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Change this app\'s aspect ratio in Settings"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Change aspect ratio"</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
index 7427b62..edc4f4e 100644
--- a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Bubble"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Manage"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bubble dismissed."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"Tap to restart this app for a better view"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Change this app\'s aspect ratio in Settings"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Change aspect ratio"</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
index 7427b62..edc4f4e 100644
--- a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Bubble"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Manage"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bubble dismissed."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"Tap to restart this app for a better view"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Change this app\'s aspect ratio in Settings"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Change aspect ratio"</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rXC/strings.xml b/libs/WindowManager/Shell/res/values-en-rXC/strings.xml
index 8498807..bdcd275 100644
--- a/libs/WindowManager/Shell/res/values-en-rXC/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rXC/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Bubble"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Manage"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bubble dismissed."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"Tap to restart this app for a better view"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Change this app\'s aspect ratio in Settings"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Change aspect ratio"</string>
diff --git a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
index 406c1f3..8653e59 100644
--- a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
+++ b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Cuadro"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Administrar"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Se descartó el cuadro."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"Presiona para reiniciar esta app y tener una mejor vista"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Cambiar la relación de aspecto de esta app en Configuración"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Cambiar relación de aspecto"</string>
diff --git a/libs/WindowManager/Shell/res/values-es/strings.xml b/libs/WindowManager/Shell/res/values-es/strings.xml
index 0583d79..8f59c9c 100644
--- a/libs/WindowManager/Shell/res/values-es/strings.xml
+++ b/libs/WindowManager/Shell/res/values-es/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Burbuja"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Gestionar"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Burbuja cerrada."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"Toca para reiniciar esta aplicación y obtener una mejor vista"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Cambiar la relación de aspecto de esta aplicación en Ajustes"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Cambiar relación de aspecto"</string>
diff --git a/libs/WindowManager/Shell/res/values-et/strings.xml b/libs/WindowManager/Shell/res/values-et/strings.xml
index 70547f5..3d86eb4 100644
--- a/libs/WindowManager/Shell/res/values-et/strings.xml
+++ b/libs/WindowManager/Shell/res/values-et/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Mull"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Halda"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Mullist loobuti."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"Puudutage, et see rakendus parema vaate jaoks taaskäivitada"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Muutke selle rakenduse kuvasuhet jaotises Seaded"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Muutke kuvasuhet"</string>
diff --git a/libs/WindowManager/Shell/res/values-eu/strings.xml b/libs/WindowManager/Shell/res/values-eu/strings.xml
index 4be35ea..4e7bdd2 100644
--- a/libs/WindowManager/Shell/res/values-eu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-eu/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Burbuila"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Kudeatu"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Baztertu da globoa."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"Hobeto ikusteko, sakatu hau, eta aplikazioa berrabiarazi egingo da"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Aldatu aplikazioaren aspektu-erlazioa ezarpenetan"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Aldatu aspektu-erlazioa"</string>
diff --git a/libs/WindowManager/Shell/res/values-fa/strings.xml b/libs/WindowManager/Shell/res/values-fa/strings.xml
index 32d5f5f..3910042 100644
--- a/libs/WindowManager/Shell/res/values-fa/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fa/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"حباب"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"مدیریت"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"حبابک رد شد."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"برای داشتن نمایی بهتر، ضربه بزنید تا این برنامه بازراهاندازی شود"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"نسبت ابعادی این برنامه را در «تنظیمات» تغییر دهید"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"تغییر نسبت ابعادی"</string>
diff --git a/libs/WindowManager/Shell/res/values-fi/strings.xml b/libs/WindowManager/Shell/res/values-fi/strings.xml
index 6f03545..577d625 100644
--- a/libs/WindowManager/Shell/res/values-fi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fi/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Kupla"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Ylläpidä"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Kupla ohitettu."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"Napauta, niin sovellus käynnistyy uudelleen paremmin näytölle sopivana"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Muuta tämän sovelluksen kuvasuhdetta Asetuksissa"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Vaihda kuvasuhdetta"</string>
diff --git a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
index 3492f13..74d822a 100644
--- a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Bulle"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Gérer"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bulle ignorée."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"Touchez pour redémarrer cette application afin d\'obtenir un meilleur affichage"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Changer les proportions de cette application dans les paramètres"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Modifier les proportions"</string>
diff --git a/libs/WindowManager/Shell/res/values-fr/strings.xml b/libs/WindowManager/Shell/res/values-fr/strings.xml
index 4002e4d..4d14d0b 100644
--- a/libs/WindowManager/Shell/res/values-fr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fr/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Bulle"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Gérer"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bulle fermée."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"Appuyez pour redémarrer cette appli et obtenir une meilleure vue."</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Modifiez le format de cette appli dans les Paramètres."</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Modifier le format"</string>
diff --git a/libs/WindowManager/Shell/res/values-gl/strings.xml b/libs/WindowManager/Shell/res/values-gl/strings.xml
index c371f7f..e5b67c2 100644
--- a/libs/WindowManager/Shell/res/values-gl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-gl/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Burbulla"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Xestionar"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Ignorouse a burbulla."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"Toca o botón para reiniciar esta aplicación e gozar dunha mellor visualización"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Cambia a proporción desta aplicación en Configuración"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Cambiar a proporción"</string>
diff --git a/libs/WindowManager/Shell/res/values-gu/strings.xml b/libs/WindowManager/Shell/res/values-gu/strings.xml
index 7e3d7a3..e2a52dc 100644
--- a/libs/WindowManager/Shell/res/values-gu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-gu/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"બબલ"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"મેનેજ કરો"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"બબલ છોડી દેવાયો."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"વધુ સારા વ્યૂ માટે, આ ઍપને ફરી શરૂ કરવા ટૅપ કરો"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"સેટિંગમાં આ ઍપનો સાપેક્ષ ગુણોત્તર બદલો"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"સાપેક્ષ ગુણોત્તર બદલો"</string>
diff --git a/libs/WindowManager/Shell/res/values-hi/strings.xml b/libs/WindowManager/Shell/res/values-hi/strings.xml
index cd0f4e3..f75e0e0 100644
--- a/libs/WindowManager/Shell/res/values-hi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hi/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"बबल"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"मैनेज करें"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"बबल खारिज किया गया."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"बेहतर व्यू पाने के लिए, टैप करके ऐप्लिकेशन को रीस्टार्ट करें"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"सेटिंग में जाकर इस ऐप्लिकेशन का आसपेक्ट रेशियो (लंबाई-चौड़ाई का अनुपात) बदलें"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"आसपेक्ट रेशियो (लंबाई-चौड़ाई का अनुपात) बदलें"</string>
diff --git a/libs/WindowManager/Shell/res/values-hr/strings.xml b/libs/WindowManager/Shell/res/values-hr/strings.xml
index 27d4cfc..ed80c50 100644
--- a/libs/WindowManager/Shell/res/values-hr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hr/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Oblačić"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Upravljanje"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Oblačić odbačen."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"Dodirnite da biste ponovo pokrenuli tu aplikaciju kako biste bolje vidjeli"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Promijeni omjer slike ove aplikacije u postavkama"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Promijeni omjer slike"</string>
diff --git a/libs/WindowManager/Shell/res/values-hu/strings.xml b/libs/WindowManager/Shell/res/values-hu/strings.xml
index a8cc5c1..32a3106 100644
--- a/libs/WindowManager/Shell/res/values-hu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hu/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Buborék"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Kezelés"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Buborék elvetve."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"A jobb nézet érdekében koppintson az alkalmazás újraindításához."</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Az app méretarányát a Beállításokban módosíthatja"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Méretarány módosítása"</string>
diff --git a/libs/WindowManager/Shell/res/values-hy/strings.xml b/libs/WindowManager/Shell/res/values-hy/strings.xml
index 7f37277..65ca704 100644
--- a/libs/WindowManager/Shell/res/values-hy/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hy/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Պղպջակ"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Կառավարել"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Ամպիկը փակվեց։"</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"Հպեք՝ հավելվածը վերագործարկելու և ավելի հարմար տեսք ընտրելու համար"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Փոխել հավելվածի կողմերի հարաբերակցությունը Կարգավորումներում"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Փոխել չափերի հարաբերակցությունը"</string>
diff --git a/libs/WindowManager/Shell/res/values-in/strings.xml b/libs/WindowManager/Shell/res/values-in/strings.xml
index 3cf55fa..975dd72 100644
--- a/libs/WindowManager/Shell/res/values-in/strings.xml
+++ b/libs/WindowManager/Shell/res/values-in/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Balon"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Kelola"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Balon ditutup."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"Ketuk untuk memulai ulang aplikasi ini agar mendapatkan tampilan yang lebih baik"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Ubah rasio aspek aplikasi ini di Setelan"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Ubah rasio aspek"</string>
diff --git a/libs/WindowManager/Shell/res/values-is/strings.xml b/libs/WindowManager/Shell/res/values-is/strings.xml
index 6aa56f9..11c4718 100644
--- a/libs/WindowManager/Shell/res/values-is/strings.xml
+++ b/libs/WindowManager/Shell/res/values-is/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Blaðra"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Stjórna"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Blöðru lokað."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"Ýttu til að endurræsa forritið og fá betri sýn"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Breyta myndhlutfalli þessa forrits í stillingunum"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Breyta myndhlutfalli"</string>
diff --git a/libs/WindowManager/Shell/res/values-it/strings.xml b/libs/WindowManager/Shell/res/values-it/strings.xml
index 3c1d5e4..168c8cc 100644
--- a/libs/WindowManager/Shell/res/values-it/strings.xml
+++ b/libs/WindowManager/Shell/res/values-it/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Fumetto"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Gestisci"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Fumetto ignorato."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"Tocca per riavviare l\'app e migliorare la visualizzazione"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Cambia le proporzioni dell\'app nelle Impostazioni"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Cambia proporzioni"</string>
diff --git a/libs/WindowManager/Shell/res/values-iw/strings.xml b/libs/WindowManager/Shell/res/values-iw/strings.xml
index a0c3b3a..fd4cd1a 100644
--- a/libs/WindowManager/Shell/res/values-iw/strings.xml
+++ b/libs/WindowManager/Shell/res/values-iw/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"בועה"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"ניהול"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"הבועה נסגרה."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"כדי לראות טוב יותר יש להקיש ולהפעיל את האפליקציה הזו מחדש"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"אפשר לשנות את יחס הגובה-רוחב של האפליקציה הזו ב\'הגדרות\'"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"שינוי יחס גובה-רוחב"</string>
diff --git a/libs/WindowManager/Shell/res/values-ja/strings.xml b/libs/WindowManager/Shell/res/values-ja/strings.xml
index fb726c1..64ddec9 100644
--- a/libs/WindowManager/Shell/res/values-ja/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ja/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"バブル"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"管理"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"ふきだしが非表示になっています。"</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"タップしてこのアプリを再起動すると、表示が適切になります"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"このアプリのアスペクト比を [設定] で変更します"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"アスペクト比を変更"</string>
diff --git a/libs/WindowManager/Shell/res/values-ka/strings.xml b/libs/WindowManager/Shell/res/values-ka/strings.xml
index e9f620a..cab8807 100644
--- a/libs/WindowManager/Shell/res/values-ka/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ka/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"ბუშტი"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"მართვა"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"ბუშტი დაიხურა."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"შეხებით გადატვირთეთ ეს აპი უკეთესი ხედის მისაღებად"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"შეცვალეთ ამ აპის თანაფარდობა პარამეტრებიდან"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"თანაფარდობის შეცვლა"</string>
diff --git a/libs/WindowManager/Shell/res/values-kk/strings.xml b/libs/WindowManager/Shell/res/values-kk/strings.xml
index 34e4103..4ff5b85 100644
--- a/libs/WindowManager/Shell/res/values-kk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-kk/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Көпіршік"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Басқару"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Қалқыма хабар жабылды."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"Көріністі жақсарту үшін осы қолданбаны түртіп, қайта ашыңыз."</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Осы қолданбаның арақатынасын параметрлерден өзгертуге болады."</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Арақатынасты өзгерту"</string>
diff --git a/libs/WindowManager/Shell/res/values-km/strings.xml b/libs/WindowManager/Shell/res/values-km/strings.xml
index 362bbad..ba7a324 100644
--- a/libs/WindowManager/Shell/res/values-km/strings.xml
+++ b/libs/WindowManager/Shell/res/values-km/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"ពពុះ"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"គ្រប់គ្រង"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"បានច្រានចោលសារលេចឡើង។"</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"ចុចដើម្បីចាប់ផ្ដើមកម្មវិធីនេះឡើងវិញសម្រាប់ទិដ្ឋភាពកាន់តែប្រសើរ"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"ផ្លាស់ប្ដូរសមាមាត្ររបស់កម្មវិធីនេះនៅក្នុងការកំណត់"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"ប្ដូរសមាមាត្រ"</string>
diff --git a/libs/WindowManager/Shell/res/values-kn/strings.xml b/libs/WindowManager/Shell/res/values-kn/strings.xml
index 77cc4a4..423e8d5 100644
--- a/libs/WindowManager/Shell/res/values-kn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-kn/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"ಬಬಲ್"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"ನಿರ್ವಹಿಸಿ"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"ಬಬಲ್ ವಜಾಗೊಳಿಸಲಾಗಿದೆ."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"ಉತ್ತಮ ವೀಕ್ಷಣೆಗಾಗಿ ಈ ಆ್ಯಪ್ ಅನ್ನು ಮರುಪ್ರಾರಂಭಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"ಸೆಟ್ಟಿಂಗ್ಗಳಲ್ಲಿ ಈ ಆ್ಯಪ್ನ ದೃಶ್ಯಾನುಪಾತವನ್ನು ಬದಲಾಯಿಸಿ"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"ದೃಶ್ಯಾನುಪಾತವನ್ನು ಬದಲಾಯಿಸಿ"</string>
diff --git a/libs/WindowManager/Shell/res/values-ko/strings.xml b/libs/WindowManager/Shell/res/values-ko/strings.xml
index caa114f..0d1c621 100644
--- a/libs/WindowManager/Shell/res/values-ko/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ko/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"버블"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"관리"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"대화창을 닫았습니다."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"탭하면 앱을 다시 시작하여 보기를 개선합니다."</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"설정에서 앱의 가로세로 비율을 변경합니다."</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"가로세로 비율 변경"</string>
diff --git a/libs/WindowManager/Shell/res/values-ky/strings.xml b/libs/WindowManager/Shell/res/values-ky/strings.xml
index 302c007..f17e9ca 100644
--- a/libs/WindowManager/Shell/res/values-ky/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ky/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Көбүк"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Башкаруу"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Калкып чыкма билдирме жабылды."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"Жакшыраак көрүү үчүн бул колдонмону өчүрүп күйгүзүңүз. Ал үчүн таптап коюңуз"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Бул колдонмонун тараптарынын катнашын параметрлерден өзгөртүү"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Тараптардын катнашын өзгөртүү"</string>
diff --git a/libs/WindowManager/Shell/res/values-lo/strings.xml b/libs/WindowManager/Shell/res/values-lo/strings.xml
index a351963..195e4d5 100644
--- a/libs/WindowManager/Shell/res/values-lo/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lo/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"ຟອງ"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"ຈັດການ"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"ປິດ Bubble ໄສ້ແລ້ວ."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"ແຕະເພື່ອຣີສະຕາດແອັບນີ້ເພື່ອມຸມມອງທີ່ດີຂຶ້ນ"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"ປ່ຽນອັດຕາສ່ວນຂອງແອັບນີ້ໃນການຕັ້ງຄ່າ"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"ປ່ຽນອັດຕາສ່ວນ"</string>
diff --git a/libs/WindowManager/Shell/res/values-lt/strings.xml b/libs/WindowManager/Shell/res/values-lt/strings.xml
index e4dd739..63ad580 100644
--- a/libs/WindowManager/Shell/res/values-lt/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lt/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Debesėlis"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Tvarkyti"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Debesėlio atsisakyta."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"Palieskite, kad iš naujo paleistumėte šią programą ir matytumėte aiškiau"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Pakeiskite šios programos kraštinių santykį"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Keisti kraštinių santykį"</string>
diff --git a/libs/WindowManager/Shell/res/values-lv/strings.xml b/libs/WindowManager/Shell/res/values-lv/strings.xml
index 99aebf6..268d893 100644
--- a/libs/WindowManager/Shell/res/values-lv/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lv/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Burbulis"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Pārvaldīt"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Burbulis ir noraidīts."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"Pieskarieties, lai restartētu šo lietotni un uzlabotu attēlojumu."</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Iestatījumos mainiet šīs lietotnes malu attiecību."</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Mainīt malu attiecību"</string>
diff --git a/libs/WindowManager/Shell/res/values-mk/strings.xml b/libs/WindowManager/Shell/res/values-mk/strings.xml
index c152c60..0a0027f 100644
--- a/libs/WindowManager/Shell/res/values-mk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mk/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Балонче"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Управувајте"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Балончето е отфрлено."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"Допрете за да ја рестартирате апликацијава за подобар приказ"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Промени го соодносот на апликацијава во „Поставки“"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Променување на соодносот"</string>
diff --git a/libs/WindowManager/Shell/res/values-ml/strings.xml b/libs/WindowManager/Shell/res/values-ml/strings.xml
index 90275cd..07809e1 100644
--- a/libs/WindowManager/Shell/res/values-ml/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ml/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"ബബിൾ"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"മാനേജ് ചെയ്യുക"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"ബബിൾ ഡിസ്മിസ് ചെയ്തു."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"മികച്ച കാഴ്ചയ്ക്കായി ഈ ആപ്പ് റീസ്റ്റാർട്ട് ചെയ്യാൻ ടാപ്പ് ചെയ്യുക"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"ഈ ആപ്പിന്റെ വീക്ഷണ അനുപാതം, ക്രമീകരണത്തിൽ മാറ്റുക"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"വീക്ഷണ അനുപാതം മാറ്റുക"</string>
diff --git a/libs/WindowManager/Shell/res/values-mn/strings.xml b/libs/WindowManager/Shell/res/values-mn/strings.xml
index 5e43506..99bd2df 100644
--- a/libs/WindowManager/Shell/res/values-mn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mn/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Бөмбөлөг"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Удирдах"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Бөмбөлгийг үл хэрэгссэн."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"Харагдах байдлыг сайжруулахын тулд энэ аппыг товшиж, дахин эхлүүлнэ үү"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Энэ аппын харьцааг Тохиргоонд өөрчилнө үү"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Харьцааг өөрчлөх"</string>
diff --git a/libs/WindowManager/Shell/res/values-mr/strings.xml b/libs/WindowManager/Shell/res/values-mr/strings.xml
index 5874bff..ac57e0a5 100644
--- a/libs/WindowManager/Shell/res/values-mr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mr/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"बबल"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"व्यवस्थापित करा"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"बबल डिसमिस केला."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"अधिक चांगल्या दृश्यासाठी हे अॅप रीस्टार्ट करण्याकरिता टॅप करा"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"सेटिंग्ज मध्ये या ॲपचा आस्पेक्ट रेशो बदला"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"आस्पेक्ट रेशो बदला"</string>
diff --git a/libs/WindowManager/Shell/res/values-ms/strings.xml b/libs/WindowManager/Shell/res/values-ms/strings.xml
index 4de8a7b..6bc2fbb 100644
--- a/libs/WindowManager/Shell/res/values-ms/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ms/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Gelembung"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Urus"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Gelembung diketepikan."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"Ketik untuk memulakan semula apl ini untuk mendapatkan paparan yang lebih baik"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Tukar nisbah bidang apl ini dalam Tetapan"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Tukar nisbah bidang"</string>
diff --git a/libs/WindowManager/Shell/res/values-my/strings.xml b/libs/WindowManager/Shell/res/values-my/strings.xml
index 5b9e9cb..12c19ed 100644
--- a/libs/WindowManager/Shell/res/values-my/strings.xml
+++ b/libs/WindowManager/Shell/res/values-my/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"ပူဖောင်းဖောက်သံ"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"စီမံရန်"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"ပူဖောင်းကွက် ဖယ်လိုက်သည်။"</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"ပိုကောင်းသောမြင်ကွင်းအတွက် ဤအက်ပ်ပြန်စရန် တို့ပါ"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"ဆက်တင်များတွင် ဤအက်ပ်၏အချိုးအစားကို ပြောင်းရန်"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"အချိုးစား ပြောင်းရန်"</string>
diff --git a/libs/WindowManager/Shell/res/values-nb/strings.xml b/libs/WindowManager/Shell/res/values-nb/strings.xml
index 6005be4..1161eb6 100644
--- a/libs/WindowManager/Shell/res/values-nb/strings.xml
+++ b/libs/WindowManager/Shell/res/values-nb/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Boble"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Administrer"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Boblen er avvist."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"Trykk for å starte denne appen på nytt og få en bedre visning"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Endre høyde/bredde-forholdet for denne appen i Innstillinger"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Endre høyde/bredde-forholdet"</string>
diff --git a/libs/WindowManager/Shell/res/values-ne/strings.xml b/libs/WindowManager/Shell/res/values-ne/strings.xml
index a5bd2ab..25d0337 100644
--- a/libs/WindowManager/Shell/res/values-ne/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ne/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"बबल"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"व्यवस्थापन गर्नुहोस्"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"बबल हटाइयो।"</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"अझ राम्रो भ्यू प्राप्त गर्नका लागि यो एप रिस्टार्ट गर्न ट्याप गर्नुहोस्"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"सेटिङमा गई यो एपको एस्पेक्ट रेसियो परिवर्तन गर्नुहोस्"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"एस्पेक्ट रेसियो परिवर्तन गर्नुहोस्"</string>
diff --git a/libs/WindowManager/Shell/res/values-nl/strings.xml b/libs/WindowManager/Shell/res/values-nl/strings.xml
index 0cd27c5..4ad343c 100644
--- a/libs/WindowManager/Shell/res/values-nl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-nl/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Bubbel"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Beheren"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bubbel gesloten."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"Tik om deze app opnieuw op te starten voor een betere weergave"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Wijzig de beeldverhouding van deze app in Instellingen"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Beeldverhouding wijzigen"</string>
diff --git a/libs/WindowManager/Shell/res/values-or/strings.xml b/libs/WindowManager/Shell/res/values-or/strings.xml
index bf75185..966d404 100644
--- a/libs/WindowManager/Shell/res/values-or/strings.xml
+++ b/libs/WindowManager/Shell/res/values-or/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"ବବଲ୍"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"ପରିଚାଳନା କରନ୍ତୁ"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"ବବଲ୍ ଖାରଜ କରାଯାଇଛି।"</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"ଏକ ଆହୁରି ଭଲ ଭ୍ୟୁ ପାଇଁ ଏହି ଆପ ରିଷ୍ଟାର୍ଟ କରିବାକୁ ଟାପ କରନ୍ତୁ"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"ସେଟିଂସରେ ଏହି ଆପର ଚଉଡ଼ା ଓ ଉଚ୍ଚତାର ଅନୁପାତ ପରିବର୍ତ୍ତନ କରନ୍ତୁ"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"ଚଉଡ଼ା ଓ ଉଚ୍ଚତାର ଅନୁପାତ ପରିବର୍ତ୍ତନ କରନ୍ତୁ"</string>
diff --git a/libs/WindowManager/Shell/res/values-pa/strings.xml b/libs/WindowManager/Shell/res/values-pa/strings.xml
index 325c1e8..9feaf41 100644
--- a/libs/WindowManager/Shell/res/values-pa/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pa/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"ਬੁਲਬੁਲਾ"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"ਪ੍ਰਬੰਧਨ ਕਰੋ"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"ਬਬਲ ਨੂੰ ਖਾਰਜ ਕੀਤਾ ਗਿਆ।"</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"ਬਿਹਤਰ ਦ੍ਰਿਸ਼ ਵਾਸਤੇ ਇਸ ਐਪ ਨੂੰ ਮੁੜ-ਸ਼ੁਰੂ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਜਾ ਕੇ ਇਸ ਐਪ ਦੇ ਆਕਾਰ ਅਨੁਪਾਤ ਨੂੰ ਬਦਲੋ"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"ਆਕਾਰ ਅਨੁਪਾਤ ਬਦਲੋ"</string>
diff --git a/libs/WindowManager/Shell/res/values-pl/strings.xml b/libs/WindowManager/Shell/res/values-pl/strings.xml
index a7648c8..1c7fbf8 100644
--- a/libs/WindowManager/Shell/res/values-pl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pl/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Dymek"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Zarządzaj"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Zamknięto dymek"</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"Kliknij w celu zrestartowania aplikacji, aby lepiej się wyświetlała."</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Zmień proporcje obrazu aplikacji w Ustawieniach"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Zmień proporcje obrazu"</string>
diff --git a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
index e47d151..5c2de2a 100644
--- a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Bolha"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Gerenciar"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Balão dispensado."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"Toque para reiniciar o app e atualizar a visualização"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Mude o tamanho da janela deste app nas Configurações"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Mudar a proporção"</string>
diff --git a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
index 1210fe8..6f76525 100644
--- a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Balão"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Gerir"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Balão ignorado."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"Toque para reiniciar esta app e ficar com uma melhor visão"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Altere o formato desta app nas Definições"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Altere o formato"</string>
diff --git a/libs/WindowManager/Shell/res/values-pt/strings.xml b/libs/WindowManager/Shell/res/values-pt/strings.xml
index e47d151..5c2de2a 100644
--- a/libs/WindowManager/Shell/res/values-pt/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Bolha"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Gerenciar"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Balão dispensado."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"Toque para reiniciar o app e atualizar a visualização"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Mude o tamanho da janela deste app nas Configurações"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Mudar a proporção"</string>
diff --git a/libs/WindowManager/Shell/res/values-ro/strings.xml b/libs/WindowManager/Shell/res/values-ro/strings.xml
index ae871f3..6e85e78 100644
--- a/libs/WindowManager/Shell/res/values-ro/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ro/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Balon"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Gestionează"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Balonul a fost respins."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"Atinge ca să repornești aplicația pentru o vizualizare mai bună"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Schimbă raportul de dimensiuni al aplicației din Setări"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Schimbă raportul de dimensiuni"</string>
diff --git a/libs/WindowManager/Shell/res/values-ru/strings.xml b/libs/WindowManager/Shell/res/values-ru/strings.xml
index 971e146..1b41983 100644
--- a/libs/WindowManager/Shell/res/values-ru/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ru/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Всплывающая подсказка"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Настроить"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Всплывающий чат закрыт."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"Нажмите, чтобы перезапустить приложение и оптимизировать размер"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Изменить соотношение сторон приложения в настройках"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Изменить соотношение сторон"</string>
diff --git a/libs/WindowManager/Shell/res/values-si/strings.xml b/libs/WindowManager/Shell/res/values-si/strings.xml
index ef1381c..6fd37e9 100644
--- a/libs/WindowManager/Shell/res/values-si/strings.xml
+++ b/libs/WindowManager/Shell/res/values-si/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"බුබුළු"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"කළමනා කරන්න"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"බුබුල ඉවත දමා ඇත."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"වඩා හොඳ දසුනක් සඳහා මෙම යෙදුම යළි ඇරඹීමට තට්ටු කරන්න"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"සැකසීම් තුළ මෙම යෙදුමේ දර්ශන අනුපාතය වෙනස් කරන්න"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"දර්ශන අනුපාතය වෙනස් කරන්න"</string>
diff --git a/libs/WindowManager/Shell/res/values-sk/strings.xml b/libs/WindowManager/Shell/res/values-sk/strings.xml
index 55a0312..dabbf39 100644
--- a/libs/WindowManager/Shell/res/values-sk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sk/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Bublina"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Spravovať"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bublina bola zavretá."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"Ak chcete zlepšiť zobrazenie, klepnutím túto aplikáciu reštartujte"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Zmeniť pomer strán tejto aplikácie v Nastaveniach"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Zmeniť pomer strán"</string>
diff --git a/libs/WindowManager/Shell/res/values-sl/strings.xml b/libs/WindowManager/Shell/res/values-sl/strings.xml
index bb123dc..3ade338 100644
--- a/libs/WindowManager/Shell/res/values-sl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sl/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Mehurček"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Upravljanje"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Oblaček je bil opuščen."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"Če želite boljši prikaz, se dotaknite za vnovični zagon te aplikacije."</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Razmerje stranic te aplikacije spremenite v nastavitvah."</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Sprememba razmerja stranic"</string>
diff --git a/libs/WindowManager/Shell/res/values-sq/strings.xml b/libs/WindowManager/Shell/res/values-sq/strings.xml
index c74a8cd..ee1aa00 100644
--- a/libs/WindowManager/Shell/res/values-sq/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sq/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Flluskë"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Menaxho"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Flluska u hoq."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"Trokit për ta rinisur këtë aplikacion për një pamje më të mirë"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Ndrysho raportin e pamjes së këtij aplikacioni te \"Cilësimet\""</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Ndrysho raportin e pamjes"</string>
diff --git a/libs/WindowManager/Shell/res/values-sr/strings.xml b/libs/WindowManager/Shell/res/values-sr/strings.xml
index 0694a97..b2868ca 100644
--- a/libs/WindowManager/Shell/res/values-sr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sr/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Облачић"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Управљајте"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Облачић је одбачен."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"Додирните да бисте рестартовали ову апликацију ради бољег приказа"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Промените размеру ове апликације у Подешавањима"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Промени размеру"</string>
diff --git a/libs/WindowManager/Shell/res/values-sv/strings.xml b/libs/WindowManager/Shell/res/values-sv/strings.xml
index 8e0bcfe..66118ef 100644
--- a/libs/WindowManager/Shell/res/values-sv/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sv/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Bubbla"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Hantera"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bubblan ignorerades."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"Tryck för att starta om appen och få en bättre vy"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Ändra appens bildformat i inställningarna"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Ändra bildformat"</string>
diff --git a/libs/WindowManager/Shell/res/values-sw/strings.xml b/libs/WindowManager/Shell/res/values-sw/strings.xml
index 41180ab..863b49b 100644
--- a/libs/WindowManager/Shell/res/values-sw/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sw/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Kiputo"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Dhibiti"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Umeondoa kiputo."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"Gusa ili uzime kisha uwashe programu hii, ili upate mwonekano bora"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Badilisha uwiano wa programu hii katika Mipangilio"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Badilisha uwiano wa kipengele"</string>
diff --git a/libs/WindowManager/Shell/res/values-ta/strings.xml b/libs/WindowManager/Shell/res/values-ta/strings.xml
index 01ac78d..74e0207 100644
--- a/libs/WindowManager/Shell/res/values-ta/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ta/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"பபிள்"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"நிர்வகி"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"குமிழ் நிராகரிக்கப்பட்டது."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"இங்கு தட்டுவதன் மூலம் இந்த ஆப்ஸை மீண்டும் தொடங்கி, ஆப்ஸ் காட்டப்படும் விதத்தை இன்னும் சிறப்பாக்கலாம்"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"அமைப்புகளில் இந்த ஆப்ஸின் தோற்ற விகிதத்தை மாற்றும்"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"தோற்ற விகிதத்தை மாற்றும்"</string>
diff --git a/libs/WindowManager/Shell/res/values-te/strings.xml b/libs/WindowManager/Shell/res/values-te/strings.xml
index 6224e72..3571156 100644
--- a/libs/WindowManager/Shell/res/values-te/strings.xml
+++ b/libs/WindowManager/Shell/res/values-te/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"బబుల్"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"మేనేజ్ చేయండి"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"బబుల్ విస్మరించబడింది."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"మెరుగైన వీక్షణ కోసం ఈ యాప్ను రీస్టార్ట్ చేయడానికి ట్యాప్ చేయండి"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"సెట్టింగ్లలో ఈ యాప్ ఆకార నిష్పత్తిని మార్చండి"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"ఆకార నిష్పత్తిని మార్చండి"</string>
diff --git a/libs/WindowManager/Shell/res/values-th/strings.xml b/libs/WindowManager/Shell/res/values-th/strings.xml
index fe0b74c..4769416 100644
--- a/libs/WindowManager/Shell/res/values-th/strings.xml
+++ b/libs/WindowManager/Shell/res/values-th/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"บับเบิล"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"จัดการ"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"ปิดบับเบิลแล้ว"</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"แตะเพื่อรีสตาร์ทแอปนี้และรับมุมมองที่ดียิ่งขึ้น"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"เปลี่ยนสัดส่วนภาพของแอปนี้ในการตั้งค่า"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"เปลี่ยนอัตราส่วนกว้างยาว"</string>
diff --git a/libs/WindowManager/Shell/res/values-tl/strings.xml b/libs/WindowManager/Shell/res/values-tl/strings.xml
index 786e99c..be18d88 100644
--- a/libs/WindowManager/Shell/res/values-tl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-tl/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Bubble"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Pamahalaan"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Na-dismiss na ang bubble."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"I-tap para i-restart ang app na ito para sa mas magandang view"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Baguhin ang aspect ratio ng app na ito sa Mga Setting"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Baguhin ang aspect ratio"</string>
diff --git a/libs/WindowManager/Shell/res/values-tr/strings.xml b/libs/WindowManager/Shell/res/values-tr/strings.xml
index e953f58..4c8c536 100644
--- a/libs/WindowManager/Shell/res/values-tr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-tr/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Baloncuk"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Yönet"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Balon kapatıldı."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"Bu uygulamayı yeniden başlatarak daha iyi bir görünüm elde etmek için dokunun"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Bu uygulamanın en boy oranını Ayarlar\'dan değiştirin"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"En boy oranını değiştir"</string>
diff --git a/libs/WindowManager/Shell/res/values-uk/strings.xml b/libs/WindowManager/Shell/res/values-uk/strings.xml
index fbdf42e..7cc1a04 100644
--- a/libs/WindowManager/Shell/res/values-uk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-uk/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Спливаюче сповіщення"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Налаштувати"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Спливаюче сповіщення закрито."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"Натисніть, щоб перезапустити цей додаток для зручнішого перегляду"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Змінити формат для цього додатка в налаштуваннях"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Змінити формат"</string>
diff --git a/libs/WindowManager/Shell/res/values-ur/strings.xml b/libs/WindowManager/Shell/res/values-ur/strings.xml
index 5562fa7..8b9f299 100644
--- a/libs/WindowManager/Shell/res/values-ur/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ur/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"بلبلہ"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"نظم کریں"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"بلبلہ برخاست کر دیا گیا۔"</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"بہتر منظر کے لیے اس ایپ کو ری اسٹارٹ کرنے کی خاطر تھپتھپائیں"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"ترتیبات میں اس ایپ کی تناسبی شرح کو تبدیل کریں"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"تناسبی شرح کو تبدیل کریں"</string>
diff --git a/libs/WindowManager/Shell/res/values-uz/strings.xml b/libs/WindowManager/Shell/res/values-uz/strings.xml
index 50e4232..55c6b32 100644
--- a/libs/WindowManager/Shell/res/values-uz/strings.xml
+++ b/libs/WindowManager/Shell/res/values-uz/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Pufaklar"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Boshqarish"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bulutcha yopildi."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"Yaxshiroq koʻrish maqsadida bu ilovani qayta ishga tushirish uchun bosing"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Sozlamalar orqali bu ilovaning tomonlar nisbatini oʻzgartiring"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Tomonlar nisbatini oʻzgartirish"</string>
diff --git a/libs/WindowManager/Shell/res/values-vi/strings.xml b/libs/WindowManager/Shell/res/values-vi/strings.xml
index 6da8588..07a6b6f 100644
--- a/libs/WindowManager/Shell/res/values-vi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-vi/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Bong bóng"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Quản lý"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Đã đóng bong bóng."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"Nhấn nút khởi động lại ứng dụng này để xem dễ hơn"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Thay đổi tỷ lệ khung hình của ứng dụng này thông qua phần Cài đặt"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Thay đổi tỷ lệ khung hình"</string>
diff --git a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
index 4318caf..908095a 100644
--- a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"气泡"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"管理"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"已关闭消息气泡。"</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"点按即可重启此应用,获得更好的视觉体验"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"在“设置”中更改此应用的宽高比"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"更改高宽比"</string>
diff --git a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
index 72cd39d..c8550b4 100644
--- a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"氣泡"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"管理"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"對話氣泡已關閉。"</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"輕按並重新啟動此應用程式,以取得更佳的觀看體驗"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"前往「設定」變更此應用程式的長寬比"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"變更長寬比"</string>
diff --git a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
index c06d7b1..6704833 100644
--- a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"泡泡"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"管理"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"已關閉泡泡。"</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"輕觸此按鈕重新啟動這個應用程式,即可獲得更良好的觀看體驗"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"前往「設定」變更這個應用程式的顯示比例"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"變更顯示比例"</string>
diff --git a/libs/WindowManager/Shell/res/values-zu/strings.xml b/libs/WindowManager/Shell/res/values-zu/strings.xml
index 755414e..96b4faec 100644
--- a/libs/WindowManager/Shell/res/values-zu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zu/strings.xml
@@ -84,6 +84,10 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Ibhamuza"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Phatha"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Ibhamuza licashisiwe."</string>
+ <!-- no translation found for bubble_shortcut_label (666269077944378311) -->
+ <skip />
+ <!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
+ <skip />
<string name="restart_button_description" msgid="4564728020654658478">"Thepha ukuze uqale kabusha le app ukuze ibonakale kangcono"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Shintsha ukubukeka kwesilinganiselo kwe-app kuMasethingi"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Shintsha ukubukeka kwesilinganiselo"</string>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java
index a426b20..5a42817 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java
@@ -31,6 +31,7 @@
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.content.Context;
+import android.graphics.Point;
import android.graphics.Rect;
import android.os.IBinder;
import android.util.ArraySet;
@@ -45,6 +46,7 @@
import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.window.flags.Flags;
import com.android.wm.shell.activityembedding.ActivityEmbeddingAnimationAdapter.SnapshotAdapter;
import com.android.wm.shell.common.ScreenshotUtils;
import com.android.wm.shell.shared.TransitionUtil;
@@ -398,7 +400,15 @@
// This is because the TaskFragment surface/change won't contain the Activity's before its
// reparent.
Animation changeAnimation = null;
- Rect parentBounds = new Rect();
+ final Rect parentBounds = new Rect();
+ // We use a single boolean value to record the backdrop override because the override used
+ // for overlay and we restrict to single overlay animation. We should fix the assumption
+ // if we allow multiple overlay transitions.
+ // The backdrop logic is mainly for animations of split animations. The backdrop should be
+ // disabled if there is any open/close target in the same transition as the change target.
+ // However, the overlay change animation usually contains one change target, and shows
+ // backdrop unexpectedly.
+ Boolean overrideShowBackdrop = null;
for (TransitionInfo.Change change : info.getChanges()) {
if (change.getMode() != TRANSIT_CHANGE
|| change.getStartAbsBounds().equals(change.getEndAbsBounds())) {
@@ -421,17 +431,17 @@
}
}
- // The TaskFragment may be enter/exit split, so we take the union of both as the parent
- // size.
- parentBounds.union(boundsAnimationChange.getStartAbsBounds());
- parentBounds.union(boundsAnimationChange.getEndAbsBounds());
- if (boundsAnimationChange != change) {
- // Union the change starting bounds in case the activity is resized and reparented
- // to a TaskFragment. In that case, the TaskFragment may not cover the activity's
- // starting bounds.
- parentBounds.union(change.getStartAbsBounds());
+ final TransitionInfo.AnimationOptions options = boundsAnimationChange
+ .getAnimationOptions();
+ if (options != null) {
+ final Animation overrideAnimation = mAnimationSpec.loadCustomAnimationFromOptions(
+ options, TRANSIT_CHANGE);
+ if (overrideAnimation != null) {
+ overrideShowBackdrop = overrideAnimation.getShowBackdrop();
+ }
}
+ calculateParentBounds(change, boundsAnimationChange, parentBounds);
// There are two animations in the array. The first one is for the start leash
// (snapshot), and the second one is for the end leash (TaskFragment).
final Animation[] animations = mAnimationSpec.createChangeBoundsChangeAnimations(change,
@@ -466,7 +476,7 @@
// If there is no corresponding open/close window with the change, we should show background
// color to cover the empty part of the screen.
- boolean shouldShouldBackgroundColor = true;
+ boolean shouldShowBackgroundColor = true;
// Handle the other windows that don't have bounds change in the same transition.
for (TransitionInfo.Change change : info.getChanges()) {
if (handledChanges.contains(change)) {
@@ -483,16 +493,18 @@
animation = ActivityEmbeddingAnimationSpec.createNoopAnimation(change);
} else if (TransitionUtil.isClosingType(change.getMode())) {
animation = mAnimationSpec.createChangeBoundsCloseAnimation(change, parentBounds);
- shouldShouldBackgroundColor = false;
+ shouldShowBackgroundColor = false;
} else {
animation = mAnimationSpec.createChangeBoundsOpenAnimation(change, parentBounds);
- shouldShouldBackgroundColor = false;
+ shouldShowBackgroundColor = false;
}
adapters.add(new ActivityEmbeddingAnimationAdapter(animation, change,
TransitionUtil.getRootFor(change, info)));
}
- if (shouldShouldBackgroundColor && changeAnimation != null) {
+ shouldShowBackgroundColor = overrideShowBackdrop != null
+ ? overrideShowBackdrop : shouldShowBackgroundColor;
+ if (shouldShowBackgroundColor && changeAnimation != null) {
// Change animation may leave part of the screen empty. Show background color to cover
// that.
changeAnimation.setShowBackdrop(true);
@@ -502,6 +514,39 @@
}
/**
+ * Calculates parent bounds of the animation target by {@code change}.
+ */
+ @VisibleForTesting
+ static void calculateParentBounds(@NonNull TransitionInfo.Change change,
+ @NonNull TransitionInfo.Change boundsAnimationChange, @NonNull Rect outParentBounds) {
+ if (Flags.activityEmbeddingOverlayPresentationFlag()) {
+ final Point endParentSize = change.getEndParentSize();
+ if (endParentSize.equals(0, 0)) {
+ return;
+ }
+ final Point endRelPosition = change.getEndRelOffset();
+ final Point endAbsPosition = new Point(change.getEndAbsBounds().left,
+ change.getEndAbsBounds().top);
+ final Point parentEndAbsPosition = new Point(endAbsPosition.x - endRelPosition.x,
+ endAbsPosition.y - endRelPosition.y);
+ outParentBounds.set(parentEndAbsPosition.x, parentEndAbsPosition.y,
+ parentEndAbsPosition.x + endParentSize.x,
+ parentEndAbsPosition.y + endParentSize.y);
+ } else {
+ // The TaskFragment may be enter/exit split, so we take the union of both as
+ // the parent size.
+ outParentBounds.union(boundsAnimationChange.getStartAbsBounds());
+ outParentBounds.union(boundsAnimationChange.getEndAbsBounds());
+ if (boundsAnimationChange != change) {
+ // Union the change starting bounds in case the activity is resized and
+ // reparented to a TaskFragment. In that case, the TaskFragment may not cover
+ // the activity's starting bounds.
+ outParentBounds.union(change.getStartAbsBounds());
+ }
+ }
+ }
+
+ /**
* Takes a screenshot of the given {@code screenshotChange} surface if WM Core hasn't taken one.
* The screenshot leash should be attached to the {@code animationChange} surface which we will
* animate later.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java
index b986862..8d49614 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java
@@ -18,6 +18,8 @@
import static android.app.ActivityOptions.ANIM_CUSTOM;
+import static android.view.WindowManager.TRANSIT_CHANGE;
+import static android.window.TransitionInfo.AnimationOptions.DEFAULT_ANIMATION_RESOURCES_ID;
import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_NONE;
import static com.android.wm.shell.transition.TransitionAnimationHelper.loadAttributeAnimation;
@@ -27,6 +29,8 @@
import android.annotation.Nullable;
import android.content.Context;
import android.graphics.Rect;
+import android.util.Log;
+import android.view.WindowManager;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
@@ -203,7 +207,7 @@
Animation loadOpenAnimation(@NonNull TransitionInfo info,
@NonNull TransitionInfo.Change change, @NonNull Rect wholeAnimationBounds) {
final boolean isEnter = TransitionUtil.isOpeningType(change.getMode());
- final Animation customAnimation = loadCustomAnimation(info, change, isEnter);
+ final Animation customAnimation = loadCustomAnimation(info, change);
final Animation animation;
if (customAnimation != null) {
animation = customAnimation;
@@ -230,7 +234,7 @@
Animation loadCloseAnimation(@NonNull TransitionInfo info,
@NonNull TransitionInfo.Change change, @NonNull Rect wholeAnimationBounds) {
final boolean isEnter = TransitionUtil.isOpeningType(change.getMode());
- final Animation customAnimation = loadCustomAnimation(info, change, isEnter);
+ final Animation customAnimation = loadCustomAnimation(info, change);
final Animation animation;
if (customAnimation != null) {
animation = customAnimation;
@@ -263,18 +267,40 @@
@Nullable
private Animation loadCustomAnimation(@NonNull TransitionInfo info,
- @NonNull TransitionInfo.Change change, boolean isEnter) {
+ @NonNull TransitionInfo.Change change) {
final TransitionInfo.AnimationOptions options;
if (Flags.moveAnimationOptionsToChange()) {
options = change.getAnimationOptions();
} else {
options = info.getAnimationOptions();
}
+ return loadCustomAnimationFromOptions(options, change.getMode());
+ }
+
+ @Nullable
+ Animation loadCustomAnimationFromOptions(@Nullable TransitionInfo.AnimationOptions options,
+ @WindowManager.TransitionType int mode) {
if (options == null || options.getType() != ANIM_CUSTOM) {
return null;
}
+ final int resId;
+ if (TransitionUtil.isOpeningType(mode)) {
+ resId = options.getEnterResId();
+ } else if (TransitionUtil.isClosingType(mode)) {
+ resId = options.getExitResId();
+ } else if (mode == TRANSIT_CHANGE) {
+ resId = options.getChangeResId();
+ } else {
+ Log.w(TAG, "Unknown transit type:" + mode);
+ resId = DEFAULT_ANIMATION_RESOURCES_ID;
+ }
+ // Use the default animation if the resources ID is not specified.
+ if (resId == DEFAULT_ANIMATION_RESOURCES_ID) {
+ return null;
+ }
+
final Animation anim = mTransitionAnimation.loadAnimationRes(options.getPackageName(),
- isEnter ? options.getEnterResId() : options.getExitResId());
+ resId);
if (anim != null) {
return anim;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
index c2242a8..2234041 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
@@ -336,11 +336,6 @@
setTouching();
mStartPos = touchPos;
mMoving = false;
- // This triggers initialization of things like the resize veil in preparation for
- // showing it when the user moves the divider past the slop, and has to be done
- // before onStartDragging() which starts the jank interaction tracing
- mSplitLayout.updateDividerBounds(mSplitLayout.getDividerPosition(),
- false /* shouldUseParallaxEffect */);
mSplitLayout.onStartDragging();
break;
case MotionEvent.ACTION_MOVE:
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/Android.bp b/libs/WindowManager/Shell/tests/flicker/splitscreen/Android.bp
index 0fe7a16b..3f2603a 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/Android.bp
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/Android.bp
@@ -37,17 +37,51 @@
"src/**/B*.kt",
"src/**/C*.kt",
"src/**/D*.kt",
- "src/**/E*.kt",
],
}
filegroup {
name: "WMShellFlickerTestsSplitScreenGroup2-src",
srcs: [
+ "src/**/E*.kt",
+ ],
+}
+
+filegroup {
+ name: "WMShellFlickerTestsSplitScreenGroup3-src",
+ srcs: [
+ "src/**/S*.kt",
+ ],
+}
+
+filegroup {
+ name: "WMShellFlickerTestsSplitScreenGroupOther-src",
+ srcs: [
"src/**/*.kt",
],
}
+java_library {
+ name: "WMShellFlickerTestsSplitScreenBase",
+ srcs: [
+ ":WMShellFlickerTestsSplitScreenBase-src",
+ ],
+ static_libs: [
+ "WMShellFlickerTestsBase",
+ "wm-shell-flicker-utils",
+ "androidx.test.ext.junit",
+ "flickertestapplib",
+ "flickerlib",
+ "flickerlib-helpers",
+ "flickerlib-trace_processor_shell",
+ "platform-test-annotations",
+ "wm-flicker-common-app-helpers",
+ "wm-flicker-common-assertions",
+ "launcher-helper-lib",
+ "launcher-aosp-tapl",
+ ],
+}
+
android_test {
name: "WMShellFlickerTestsSplitScreenGroup1",
defaults: ["WMShellFlickerTestsDefault"],
@@ -56,10 +90,12 @@
instrumentation_target_package: "com.android.wm.shell.flicker.splitscreen",
test_config_template: "AndroidTestTemplate.xml",
srcs: [
- ":WMShellFlickerTestsSplitScreenBase-src",
":WMShellFlickerTestsSplitScreenGroup1-src",
],
- static_libs: ["WMShellFlickerTestsBase"],
+ static_libs: [
+ "WMShellFlickerTestsBase",
+ "WMShellFlickerTestsSplitScreenBase",
+ ],
data: ["trace_config/*"],
}
@@ -71,12 +107,50 @@
instrumentation_target_package: "com.android.wm.shell.flicker.splitscreen",
test_config_template: "AndroidTestTemplate.xml",
srcs: [
- ":WMShellFlickerTestsSplitScreenBase-src",
- ":WMShellFlickerTestsSplitScreenGroup2-src",
+ ":WMShellFlickerTestsSplitScreenGroup1-src",
+ ],
+ static_libs: [
+ "WMShellFlickerTestsBase",
+ "WMShellFlickerTestsSplitScreenBase",
+ ],
+ data: ["trace_config/*"],
+}
+
+android_test {
+ name: "WMShellFlickerTestsSplitScreenGroup3",
+ defaults: ["WMShellFlickerTestsDefault"],
+ manifest: "AndroidManifest.xml",
+ package_name: "com.android.wm.shell.flicker.splitscreen",
+ instrumentation_target_package: "com.android.wm.shell.flicker.splitscreen",
+ test_config_template: "AndroidTestTemplate.xml",
+ srcs: [
+ ":WMShellFlickerTestsSplitScreenGroup1-src",
+ ],
+ static_libs: [
+ "WMShellFlickerTestsBase",
+ "WMShellFlickerTestsSplitScreenBase",
+ ],
+ data: ["trace_config/*"],
+}
+
+android_test {
+ name: "WMShellFlickerTestsSplitScreenGroupOther",
+ defaults: ["WMShellFlickerTestsDefault"],
+ manifest: "AndroidManifest.xml",
+ package_name: "com.android.wm.shell.flicker.splitscreen",
+ instrumentation_target_package: "com.android.wm.shell.flicker.splitscreen",
+ test_config_template: "AndroidTestTemplate.xml",
+ srcs: [
+ ":WMShellFlickerTestsSplitScreenGroupOther-src",
],
exclude_srcs: [
":WMShellFlickerTestsSplitScreenGroup1-src",
+ ":WMShellFlickerTestsSplitScreenGroup2-src",
+ ":WMShellFlickerTestsSplitScreenGroup3-src",
],
- static_libs: ["WMShellFlickerTestsBase"],
+ static_libs: [
+ "WMShellFlickerTestsBase",
+ "WMShellFlickerTestsSplitScreenBase",
+ ],
data: ["trace_config/*"],
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunnerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunnerTests.java
index bd20c11..731f75bf 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunnerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunnerTests.java
@@ -20,9 +20,11 @@
import static android.window.TransitionInfo.FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY;
import static android.window.TransitionInfo.FLAG_IS_BEHIND_STARTING_WINDOW;
+import static com.android.wm.shell.activityembedding.ActivityEmbeddingAnimationRunner.calculateParentBounds;
import static com.android.wm.shell.transition.Transitions.TRANSIT_TASK_FRAGMENT_DRAG_RESIZE;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doNothing;
@@ -32,6 +34,9 @@
import static org.mockito.Mockito.verifyNoMoreInteractions;
import android.animation.Animator;
+import android.annotation.NonNull;
+import android.graphics.Point;
+import android.graphics.Rect;
import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
@@ -130,7 +135,7 @@
@Test
public void testInvalidCustomAnimation_disableAnimationOptionsPerChange() {
final TransitionInfo info = new TransitionInfoBuilder(TRANSIT_OPEN, 0)
- .addChange(createChange(FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY))
+ .addChange(createChange(FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY, TRANSIT_OPEN))
.build();
info.setAnimationOptions(TransitionInfo.AnimationOptions
.makeCustomAnimOptions("packageName", 0 /* enterResId */, 0 /* exitResId */,
@@ -148,7 +153,7 @@
@Test
public void testInvalidCustomAnimation_enableAnimationOptionsPerChange() {
final TransitionInfo info = new TransitionInfoBuilder(TRANSIT_OPEN, 0)
- .addChange(createChange(FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY))
+ .addChange(createChange(FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY, TRANSIT_OPEN))
.build();
info.getChanges().getFirst().setAnimationOptions(TransitionInfo.AnimationOptions
.makeCustomAnimOptions("packageName", 0 /* enterResId */, 0 /* exitResId */,
@@ -161,4 +166,128 @@
// An invalid custom animation is equivalent to jump-cut.
assertEquals(0, animator.getDuration());
}
+
+ @DisableFlags(Flags.FLAG_ACTIVITY_EMBEDDING_OVERLAY_PRESENTATION_FLAG)
+ @Test
+ public void testCalculateParentBounds_flagDisabled() {
+ final Rect parentBounds = new Rect(0, 0, 2000, 2000);
+ final Rect primaryBounds = new Rect();
+ final Rect secondaryBounds = new Rect();
+ parentBounds.splitVertically(primaryBounds, secondaryBounds);
+
+ final TransitionInfo.Change change = createChange(0 /* flags */);
+ change.setStartAbsBounds(secondaryBounds);
+
+ final TransitionInfo.Change boundsAnimationChange = createChange(0 /* flags */);
+ boundsAnimationChange.setStartAbsBounds(primaryBounds);
+ boundsAnimationChange.setEndAbsBounds(primaryBounds);
+ final Rect actualParentBounds = new Rect();
+
+ calculateParentBounds(change, boundsAnimationChange, actualParentBounds);
+
+ assertEquals(parentBounds, actualParentBounds);
+
+ actualParentBounds.setEmpty();
+
+ boundsAnimationChange.setStartAbsBounds(secondaryBounds);
+ boundsAnimationChange.setEndAbsBounds(primaryBounds);
+
+ calculateParentBounds(boundsAnimationChange, boundsAnimationChange, actualParentBounds);
+
+ assertEquals(parentBounds, actualParentBounds);
+ }
+
+ // TODO(b/243518738): Rewrite with TestParameter
+ @EnableFlags(Flags.FLAG_ACTIVITY_EMBEDDING_OVERLAY_PRESENTATION_FLAG)
+ @Test
+ public void testCalculateParentBounds_flagEnabled() {
+ TransitionInfo.Change change;
+ final TransitionInfo.Change stubChange = createChange(0 /* flags */);
+ final Rect actualParentBounds = new Rect();
+ Rect parentBounds = new Rect(0, 0, 2000, 2000);
+ Rect endAbsBounds = new Rect(0, 0, 2000, 2000);
+ change = prepareChangeForParentBoundsCalculationTest(
+ new Point(0, 0) /* endRelOffset */,
+ endAbsBounds,
+ new Point() /* endParentSize */
+ );
+
+ calculateParentBounds(change, stubChange, actualParentBounds);
+
+ assertTrue("Parent bounds must be empty because end parent size is not set.",
+ actualParentBounds.isEmpty());
+
+ String testString = "Parent start with (0, 0)";
+ change = prepareChangeForParentBoundsCalculationTest(
+ new Point(endAbsBounds.left - parentBounds.left,
+ endAbsBounds.top - parentBounds.top),
+ endAbsBounds, new Point(parentBounds.width(), parentBounds.height()));
+
+ calculateParentBounds(change, stubChange, actualParentBounds);
+
+ assertEquals(testString + ": Parent bounds must be " + parentBounds, parentBounds,
+ actualParentBounds);
+
+ testString = "Container not start with (0, 0)";
+ parentBounds = new Rect(0, 0, 2000, 2000);
+ endAbsBounds = new Rect(1000, 500, 2000, 1500);
+ change = prepareChangeForParentBoundsCalculationTest(
+ new Point(endAbsBounds.left - parentBounds.left,
+ endAbsBounds.top - parentBounds.top),
+ endAbsBounds, new Point(parentBounds.width(), parentBounds.height()));
+
+ calculateParentBounds(change, stubChange, actualParentBounds);
+
+ assertEquals(testString + ": Parent bounds must be " + parentBounds, parentBounds,
+ actualParentBounds);
+
+ testString = "Parent container on the right";
+ parentBounds = new Rect(1000, 0, 2000, 2000);
+ endAbsBounds = new Rect(1000, 500, 1500, 1500);
+ change = prepareChangeForParentBoundsCalculationTest(
+ new Point(endAbsBounds.left - parentBounds.left,
+ endAbsBounds.top - parentBounds.top),
+ endAbsBounds, new Point(parentBounds.width(), parentBounds.height()));
+
+ calculateParentBounds(change, stubChange, actualParentBounds);
+
+ assertEquals(testString + ": Parent bounds must be " + parentBounds, parentBounds,
+ actualParentBounds);
+
+ testString = "Parent container on the bottom";
+ parentBounds = new Rect(0, 1000, 2000, 2000);
+ endAbsBounds = new Rect(500, 1500, 1500, 2000);
+ change = prepareChangeForParentBoundsCalculationTest(
+ new Point(endAbsBounds.left - parentBounds.left,
+ endAbsBounds.top - parentBounds.top),
+ endAbsBounds, new Point(parentBounds.width(), parentBounds.height()));
+
+ calculateParentBounds(change, stubChange, actualParentBounds);
+
+ assertEquals(testString + ": Parent bounds must be " + parentBounds, parentBounds,
+ actualParentBounds);
+
+ testString = "Parent container in the middle";
+ parentBounds = new Rect(500, 500, 1500, 1500);
+ endAbsBounds = new Rect(1000, 500, 1500, 1000);
+ change = prepareChangeForParentBoundsCalculationTest(
+ new Point(endAbsBounds.left - parentBounds.left,
+ endAbsBounds.top - parentBounds.top),
+ endAbsBounds, new Point(parentBounds.width(), parentBounds.height()));
+
+ calculateParentBounds(change, stubChange, actualParentBounds);
+
+ assertEquals(testString + ": Parent bounds must be " + parentBounds, parentBounds,
+ actualParentBounds);
+ }
+
+ @NonNull
+ private static TransitionInfo.Change prepareChangeForParentBoundsCalculationTest(
+ @NonNull Point endRelOffset, @NonNull Rect endAbsBounds, @NonNull Point endParentSize) {
+ final TransitionInfo.Change change = createChange(0 /* flags */);
+ change.setEndRelOffset(endRelOffset.x, endRelOffset.y);
+ change.setEndAbsBounds(endAbsBounds);
+ change.setEndParentSize(endParentSize.x, endParentSize.y);
+ return change;
+ }
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationTestBase.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationTestBase.java
index 0b2265d..c18d7ec 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationTestBase.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationTestBase.java
@@ -16,6 +16,7 @@
package com.android.wm.shell.activityembedding;
+import static android.view.WindowManager.TRANSIT_NONE;
import static android.window.TransitionInfo.FLAG_FILLS_TASK;
import static android.window.TransitionInfo.FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY;
@@ -31,6 +32,7 @@
import android.graphics.Rect;
import android.os.IBinder;
import android.view.SurfaceControl;
+import android.view.WindowManager;
import android.window.TransitionInfo;
import android.window.WindowContainerToken;
@@ -82,11 +84,27 @@
spyOn(mFinishCallback);
}
- /** Creates a mock {@link TransitionInfo.Change}. */
+ /**
+ * Creates a mock {@link TransitionInfo.Change}.
+ *
+ * @param flags the {@link TransitionInfo.ChangeFlags} of the change
+ */
static TransitionInfo.Change createChange(@TransitionInfo.ChangeFlags int flags) {
+ return createChange(flags, TRANSIT_NONE);
+ }
+
+ /**
+ * Creates a mock {@link TransitionInfo.Change}.
+ *
+ * @param flags the {@link TransitionInfo.ChangeFlags} of the change
+ * @param mode the transition mode of the change
+ */
+ static TransitionInfo.Change createChange(@TransitionInfo.ChangeFlags int flags,
+ @WindowManager.TransitionType int mode) {
TransitionInfo.Change c = new TransitionInfo.Change(mock(WindowContainerToken.class),
mock(SurfaceControl.class));
c.setFlags(flags);
+ c.setMode(mode);
return c;
}
diff --git a/native/android/Android.bp b/native/android/Android.bp
index 8945bd1..c4c4102 100644
--- a/native/android/Android.bp
+++ b/native/android/Android.bp
@@ -41,6 +41,7 @@
"-Wextra",
"-Wunused",
"-Wunreachable-code",
+ "-Wthread-safety",
],
}
diff --git a/native/android/performance_hint.cpp b/native/android/performance_hint.cpp
index 44fa677..7e5bef1 100644
--- a/native/android/performance_hint.cpp
+++ b/native/android/performance_hint.cpp
@@ -23,6 +23,7 @@
#include <aidl/android/os/IHintManager.h>
#include <aidl/android/os/IHintSession.h>
#include <android-base/stringprintf.h>
+#include <android-base/thread_annotations.h>
#include <android/binder_manager.h>
#include <android/binder_status.h>
#include <android/performance_hint.h>
@@ -111,26 +112,26 @@
// HAL preferred update rate
const int64_t mPreferredRateNanos;
// Target duration for choosing update rate
- int64_t mTargetDurationNanos;
+ int64_t mTargetDurationNanos GUARDED_BY(sHintMutex);
// First target hit timestamp
- int64_t mFirstTargetMetTimestamp;
+ int64_t mFirstTargetMetTimestamp GUARDED_BY(sHintMutex);
// Last target hit timestamp
- int64_t mLastTargetMetTimestamp;
+ int64_t mLastTargetMetTimestamp GUARDED_BY(sHintMutex);
// Last hint reported from sendHint indexed by hint value
- std::vector<int64_t> mLastHintSentTimestamp;
+ std::vector<int64_t> mLastHintSentTimestamp GUARDED_BY(sHintMutex);
// Cached samples
- std::vector<hal::WorkDuration> mActualWorkDurations;
- std::string mSessionName;
- static int64_t sIDCounter;
+ std::vector<hal::WorkDuration> mActualWorkDurations GUARDED_BY(sHintMutex);
+ std::string mSessionName GUARDED_BY(sHintMutex);
+ static int64_t sIDCounter GUARDED_BY(sHintMutex);
// The most recent set of thread IDs
- std::vector<int32_t> mLastThreadIDs;
- std::optional<hal::SessionConfig> mSessionConfig;
+ std::vector<int32_t> mLastThreadIDs GUARDED_BY(sHintMutex);
+ std::optional<hal::SessionConfig> mSessionConfig GUARDED_BY(sHintMutex);
// Tracing helpers
- void traceThreads(std::vector<int32_t>& tids);
- void tracePowerEfficient(bool powerEfficient);
- void traceActualDuration(int64_t actualDuration);
- void traceBatchSize(size_t batchSize);
- void traceTargetDuration(int64_t targetDuration);
+ void traceThreads(std::vector<int32_t>& tids) REQUIRES(sHintMutex);
+ void tracePowerEfficient(bool powerEfficient) REQUIRES(sHintMutex);
+ void traceActualDuration(int64_t actualDuration) REQUIRES(sHintMutex);
+ void traceBatchSize(size_t batchSize) REQUIRES(sHintMutex);
+ void traceTargetDuration(int64_t targetDuration) REQUIRES(sHintMutex);
};
static std::shared_ptr<IHintManager>* gIHintManagerForTesting = nullptr;
diff --git a/native/android/thermal.cpp b/native/android/thermal.cpp
index b43f2f16..f7a3537 100644
--- a/native/android/thermal.cpp
+++ b/native/android/thermal.cpp
@@ -99,21 +99,21 @@
: mThermalSvc(std::move(service)), mServiceListener(nullptr) {}
AThermalManager::~AThermalManager() {
- std::unique_lock<std::mutex> listenerLock(mListenerMutex);
-
- mListeners.clear();
- if (mServiceListener != nullptr) {
- bool success = false;
- mThermalSvc->unregisterThermalStatusListener(mServiceListener, &success);
- mServiceListener = nullptr;
+ {
+ std::scoped_lock<std::mutex> listenerLock(mListenerMutex);
+ mListeners.clear();
+ if (mServiceListener != nullptr) {
+ bool success = false;
+ mThermalSvc->unregisterThermalStatusListener(mServiceListener, &success);
+ mServiceListener = nullptr;
+ }
}
- listenerLock.unlock();
- std::unique_lock<std::mutex> lock(mThresholdsMutex);
+ std::scoped_lock<std::mutex> lock(mThresholdsMutex);
delete[] mThresholds;
}
status_t AThermalManager::notifyStateChange(int32_t status) {
- std::unique_lock<std::mutex> lock(mListenerMutex);
+ std::scoped_lock<std::mutex> lock(mListenerMutex);
AThermalStatus thermalStatus = static_cast<AThermalStatus>(status);
for (auto listener : mListeners) {
@@ -123,7 +123,7 @@
}
status_t AThermalManager::addListener(AThermal_StatusCallback callback, void *data) {
- std::unique_lock<std::mutex> lock(mListenerMutex);
+ std::scoped_lock<std::mutex> lock(mListenerMutex);
if (callback == nullptr) {
// Callback can not be nullptr
@@ -157,7 +157,7 @@
}
status_t AThermalManager::removeListener(AThermal_StatusCallback callback, void *data) {
- std::unique_lock<std::mutex> lock(mListenerMutex);
+ std::scoped_lock<std::mutex> lock(mListenerMutex);
auto it = std::remove_if(mListeners.begin(),
mListeners.end(),
@@ -216,7 +216,7 @@
status_t AThermalManager::getThermalHeadroomThresholds(const AThermalHeadroomThreshold **result,
size_t *size) {
- std::unique_lock<std::mutex> lock(mThresholdsMutex);
+ std::scoped_lock<std::mutex> lock(mThresholdsMutex);
if (mThresholds == nullptr) {
auto thresholds = std::make_unique<std::vector<float>>();
binder::Status ret = mThermalSvc->getThermalHeadroomThresholds(thresholds.get());
diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/CredentialSelectorActivity.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/CredentialSelectorActivity.kt
index 5728c8c..35addb3 100644
--- a/packages/CredentialManager/wear/src/com/android/credentialmanager/CredentialSelectorActivity.kt
+++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/CredentialSelectorActivity.kt
@@ -24,7 +24,6 @@
import androidx.activity.viewModels
import com.android.credentialmanager.ui.theme.WearCredentialSelectorTheme
import com.android.credentialmanager.ui.WearApp
-import com.google.android.horologist.annotations.ExperimentalHorologistApi
import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint(ComponentActivity::class)
@@ -32,7 +31,6 @@
private val viewModel: CredentialSelectorViewModel by viewModels()
- @OptIn(ExperimentalHorologistApi::class)
override fun onCreate(savedInstanceState: Bundle?) {
Log.d(TAG, "onCreate, intent: $intent")
super.onCreate(savedInstanceState)
diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/components/CredentialsScreenChip.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/components/CredentialsScreenChip.kt
index c641d7f..25bc381 100644
--- a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/components/CredentialsScreenChip.kt
+++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/components/CredentialsScreenChip.kt
@@ -15,6 +15,7 @@
*/
package com.android.credentialmanager.ui.components
+import androidx.wear.compose.material.MaterialTheme as WearMaterialTheme
import androidx.compose.foundation.layout.Row
import androidx.compose.material3.Icon
import android.graphics.drawable.Drawable
@@ -22,7 +23,11 @@
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.outlined.Lock
+import androidx.compose.material.icons.outlined.LockOpen
import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
@@ -46,7 +51,7 @@
onClick: () -> Unit,
secondaryLabel: String? = null,
icon: Drawable? = null,
- isAuthenticationEntryLocked: Boolean = false,
+ isAuthenticationEntryLocked: Boolean? = null,
textAlign: TextAlign = TextAlign.Center,
modifier: Modifier = Modifier,
colors: ChipColors = ChipDefaults.secondaryChipColors()
@@ -77,7 +82,7 @@
text: @Composable () -> Unit,
secondaryLabel: String? = null,
icon: Drawable? = null,
- isAuthenticationEntryLocked: Boolean = false,
+ isAuthenticationEntryLocked: Boolean? = null,
modifier: Modifier = Modifier,
colors: ChipColors = ChipDefaults.primaryChipColors(),
) {
@@ -94,16 +99,23 @@
text = secondaryLabel,
)
- if (isAuthenticationEntryLocked)
- // TODO(b/324465527) change this to lock icon and correct size once figma mocks are
- // updated
- Icon(
- bitmap = checkNotNull(icon?.toBitmap()?.asImageBitmap()),
- // Decorative purpose only.
- contentDescription = null,
- modifier = Modifier.size(10.dp),
- tint = Color.Unspecified
- )
+ if (isAuthenticationEntryLocked != null) {
+ if (isAuthenticationEntryLocked) {
+ Icon(
+ Icons.Outlined.Lock,
+ contentDescription = null,
+ modifier = Modifier.size(12.dp).align(Alignment.CenterVertically),
+ tint = WearMaterialTheme.colors.onSurfaceVariant
+ )
+ } else {
+ Icon(
+ Icons.Outlined.LockOpen,
+ contentDescription = null,
+ modifier = Modifier.size(12.dp).align(Alignment.CenterVertically),
+ tint = WearMaterialTheme.colors.onSurfaceVariant
+ )
+ }
+ }
}
}
}
diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/components/Texts.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/components/Texts.kt
index 22f6bf0..282fea0 100644
--- a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/components/Texts.kt
+++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/components/Texts.kt
@@ -22,7 +22,6 @@
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.text.TextLayoutResult
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
@@ -57,7 +56,6 @@
text: String,
textAlign: TextAlign = TextAlign.Center,
modifier: Modifier = Modifier,
- onTextLayout: (TextLayoutResult) -> Unit = {},
) {
Text(
modifier = modifier.padding(start = 8.dp, end = 8.dp).wrapContentSize(),
@@ -67,7 +65,6 @@
overflow = TextOverflow.Ellipsis,
textAlign = textAlign,
maxLines = 2,
- onTextLayout = onTextLayout,
)
}
@@ -79,7 +76,6 @@
maxLines: Int = 1,
modifier: Modifier = Modifier,
color: Color = WearMaterialTheme.colors.onSurface,
- onTextLayout: (TextLayoutResult) -> Unit = {},
) {
Text(
modifier = modifier.wrapContentSize(),
@@ -89,7 +85,6 @@
overflow = TextOverflow.Ellipsis,
textAlign = textAlign,
maxLines = maxLines,
- onTextLayout = onTextLayout,
)
}
@@ -97,7 +92,6 @@
fun WearSecondaryLabel(
text: String,
modifier: Modifier = Modifier,
- onTextLayout: (TextLayoutResult) -> Unit = {},
) {
Text(
modifier = modifier.wrapContentSize(),
@@ -107,6 +101,5 @@
overflow = TextOverflow.Ellipsis,
textAlign = TextAlign.Start,
maxLines = 1,
- onTextLayout = onTextLayout,
)
}
diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/mappers/CredentialSelectorUiStateGetMapper.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/mappers/CredentialSelectorUiStateGetMapper.kt
index 473094c..2656275 100644
--- a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/mappers/CredentialSelectorUiStateGetMapper.kt
+++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/mappers/CredentialSelectorUiStateGetMapper.kt
@@ -43,7 +43,8 @@
var icon: Drawable? = null
// provide icon if all entries have the same provider
- if (sortedEntries.all {it.providerId == sortedEntries[0].providerId}) {
+ if (sortedEntries.isNotEmpty() &&
+ sortedEntries.all {it.providerId == sortedEntries[0].providerId}) {
icon = providerInfos[0].icon
}
diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/multiple/MultiCredentialsFlattenScreen.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/multiple/MultiCredentialsFlattenScreen.kt
index fb81e73..36e9792 100644
--- a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/multiple/MultiCredentialsFlattenScreen.kt
+++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/multiple/MultiCredentialsFlattenScreen.kt
@@ -75,7 +75,10 @@
CredentialsScreenChip(
label = credential.userName,
onClick = { selectEntry(credential, false) },
- secondaryLabel = credential.credentialTypeDisplayName,
+ secondaryLabel =
+ credential.credentialTypeDisplayName.ifEmpty {
+ credential.providerDisplayName
+ },
icon = credential.icon,
textAlign = TextAlign.Start
)
diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/multiple/MultiCredentialsFoldScreen.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/multiple/MultiCredentialsFoldScreen.kt
index 7addc74..ce2bad0 100644
--- a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/multiple/MultiCredentialsFoldScreen.kt
+++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/multiple/MultiCredentialsFoldScreen.kt
@@ -61,13 +61,12 @@
val credentials = credentialSelectorUiState.sortedEntries
item {
var title = stringResource(R.string.choose_sign_in_title)
-
- if (credentials.isEmpty()) {
- title = stringResource(R.string.choose_sign_in_title)
- } else if (credentials.all{ it.credentialType == CredentialType.PASSKEY }) {
- title = stringResource(R.string.choose_passkey_title)
- } else if (credentials.all { it.credentialType == CredentialType.PASSWORD }) {
- title = stringResource(R.string.choose_password_title)
+ if (credentials.isNotEmpty()) {
+ if (credentials.all { it.credentialType == CredentialType.PASSKEY }) {
+ title = stringResource(R.string.choose_passkey_title)
+ } else if (credentials.all { it.credentialType == CredentialType.PASSWORD }) {
+ title = stringResource(R.string.choose_password_title)
+ }
}
SignInHeader(
@@ -77,16 +76,19 @@
}
credentials.forEach { credential: CredentialEntryInfo ->
- item {
- CredentialsScreenChip(
- label = credential.userName,
- onClick = { selectEntry(credential, false) },
- secondaryLabel = credential.credentialTypeDisplayName,
- icon = credential.icon,
- )
- CredentialsScreenChipSpacer()
+ item {
+ CredentialsScreenChip(
+ label = credential.userName,
+ onClick = { selectEntry(credential, false) },
+ secondaryLabel =
+ credential.credentialTypeDisplayName.ifEmpty {
+ credential.providerDisplayName
+ },
+ icon = credential.icon,
+ )
+ CredentialsScreenChipSpacer()
+ }
}
- }
credentialSelectorUiState.authenticationEntryList.forEach { authenticationEntryInfo ->
item {
@@ -96,7 +98,6 @@
CredentialsScreenChipSpacer()
}
}
-
item {
Spacer(modifier = Modifier.size(8.dp))
}
diff --git a/packages/InputDevices/res/values-en-rCA/strings.xml b/packages/InputDevices/res/values-en-rCA/strings.xml
index 74fd7c5..3fa4bce 100644
--- a/packages/InputDevices/res/values-en-rCA/strings.xml
+++ b/packages/InputDevices/res/values-en-rCA/strings.xml
@@ -54,8 +54,6 @@
<string name="keyboard_layout_thai_pattachote" msgid="2547992342794252205">"Thai (Pattachote)"</string>
<string name="keyboard_layout_serbian_latin" msgid="3128791759390046571">"Serbian (Latin)"</string>
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"Montenegrin (Latin)"</string>
- <!-- no translation found for keyboard_layout_serbian_cyrillic (7013541044323542196) -->
- <skip />
- <!-- no translation found for keyboard_layout_montenegrin_cyrillic (2391253952894077421) -->
- <skip />
+ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Serbian (Cyrillic)"</string>
+ <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Montenegrin (Cyrillic)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-en-rXC/strings.xml b/packages/InputDevices/res/values-en-rXC/strings.xml
index 777d939..2ae35ab 100644
--- a/packages/InputDevices/res/values-en-rXC/strings.xml
+++ b/packages/InputDevices/res/values-en-rXC/strings.xml
@@ -54,8 +54,6 @@
<string name="keyboard_layout_thai_pattachote" msgid="2547992342794252205">"Thai (Pattachote)"</string>
<string name="keyboard_layout_serbian_latin" msgid="3128791759390046571">"Serbian (Latin)"</string>
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"Montenegrin (Latin)"</string>
- <!-- no translation found for keyboard_layout_serbian_cyrillic (7013541044323542196) -->
- <skip />
- <!-- no translation found for keyboard_layout_montenegrin_cyrillic (2391253952894077421) -->
- <skip />
+ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Serbian (Cyrillic)"</string>
+ <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Montenegrin (Cyrillic)"</string>
</resources>
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt
index 9a344c3..2ae3b56 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt
@@ -41,23 +41,25 @@
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ProvideTextStyle
-import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBarScrollBehavior
import androidx.compose.material3.TopAppBarState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.NonRestartableComposable
-import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.Stable
+import androidx.compose.runtime.derivedStateOf
+import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clipToBounds
+import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.graphics.lerp
+import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.layout.AlignmentLine
import androidx.compose.ui.layout.LastBaseline
import androidx.compose.ui.layout.Layout
@@ -66,6 +68,7 @@
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.semantics.clearAndSetSemantics
import androidx.compose.ui.semantics.heading
+import androidx.compose.ui.semantics.isTraversalGroup
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.style.TextOverflow
@@ -80,11 +83,10 @@
import kotlin.math.max
import kotlin.math.roundToInt
-private val windowInsets: WindowInsets
+private val safeDrawingWindowInsets: WindowInsets
@Composable
@NonRestartableComposable
- get() = WindowInsets.safeDrawing
- .only(WindowInsetsSides.Horizontal + WindowInsetsSides.Top)
+ get() = WindowInsets.safeDrawing.only(WindowInsetsSides.Horizontal + WindowInsetsSides.Top)
@Composable
internal fun CustomizedTopAppBar(
@@ -97,14 +99,12 @@
titleTextStyle = MaterialTheme.typography.titleMedium,
navigationIcon = navigationIcon,
actions = actions,
- windowInsets = windowInsets,
+ windowInsets = safeDrawingWindowInsets,
colors = topAppBarColors(),
)
}
-/**
- * The customized LargeTopAppBar for Settings.
- */
+/** The customized LargeTopAppBar for Settings. */
@OptIn(ExperimentalMaterial3Api::class)
@Composable
internal fun CustomizedLargeTopAppBar(
@@ -124,7 +124,7 @@
navigationIcon = navigationIcon,
actions = actions,
colors = topAppBarColors(),
- windowInsets = windowInsets,
+ windowInsets = safeDrawingWindowInsets,
pinnedHeight = ContainerHeight,
scrollBehavior = scrollBehavior,
)
@@ -134,38 +134,41 @@
private fun Title(title: String, maxLines: Int = Int.MAX_VALUE) {
Text(
text = title,
- modifier = Modifier.padding(
- start = SettingsDimension.itemPaddingAround,
- end = SettingsDimension.itemPaddingEnd,
- )
- .semantics { heading() },
+ modifier =
+ Modifier.padding(
+ start = SettingsDimension.itemPaddingAround,
+ end = SettingsDimension.itemPaddingEnd,
+ )
+ .semantics { heading() },
overflow = TextOverflow.Ellipsis,
maxLines = maxLines,
)
}
@Composable
-private fun topAppBarColors() = TopAppBarColors(
- containerColor = MaterialTheme.colorScheme.settingsBackground,
- scrolledContainerColor = MaterialTheme.colorScheme.surfaceVariant,
- navigationIconContentColor = MaterialTheme.colorScheme.onSurface,
- titleContentColor = MaterialTheme.colorScheme.onSurface,
- actionIconContentColor = MaterialTheme.colorScheme.onSurfaceVariant,
-)
+private fun topAppBarColors() =
+ TopAppBarColors(
+ containerColor = MaterialTheme.colorScheme.settingsBackground,
+ scrolledContainerColor = MaterialTheme.colorScheme.surfaceVariant,
+ navigationIconContentColor = MaterialTheme.colorScheme.onSurface,
+ titleContentColor = MaterialTheme.colorScheme.onSurface,
+ actionIconContentColor = MaterialTheme.colorScheme.onSurfaceVariant,
+ )
/**
* Represents the colors used by a top app bar in different states.
+ *
* This implementation animates the container color according to the top app bar scroll state. It
* does not animate the leading, headline, or trailing colors.
*
- * @constructor create an instance with arbitrary colors, see [TopAppBarColors] for a
- * factory method using the default material3 spec
* @param containerColor the color used for the background of this BottomAppBar. Use
- * [Color.Transparent] to have no color.
+ * [Color.Transparent] to have no color.
* @param scrolledContainerColor the container color when content is scrolled behind it
* @param navigationIconContentColor the content color used for the navigation icon
* @param titleContentColor the content color used for the title
* @param actionIconContentColor the content color used for actions
+ * @constructor create an instance with arbitrary colors, see [TopAppBarColors] for a factory method
+ * using the default material3 spec
*/
@Stable
private class TopAppBarColors(
@@ -180,11 +183,11 @@
* Represents the container color used for the top app bar.
*
* A [colorTransitionFraction] provides a percentage value that can be used to generate a color.
- * Usually, an app bar implementation will pass in a [colorTransitionFraction] read from
- * the [TopAppBarState.collapsedFraction] or the [TopAppBarState.overlappedFraction].
+ * Usually, an app bar implementation will pass in a [colorTransitionFraction] read from the
+ * [TopAppBarState.collapsedFraction] or the [TopAppBarState.overlappedFraction].
*
* @param colorTransitionFraction a `0.0` to `1.0` value that represents a color transition
- * percentage
+ * percentage
*/
@Stable
fun containerColor(colorTransitionFraction: Float): Color {
@@ -233,29 +236,35 @@
colors: TopAppBarColors,
) {
// Wrap the given actions in a Row.
- val actionsRow = @Composable {
- Row(
- horizontalArrangement = Arrangement.End,
- verticalAlignment = Alignment.CenterVertically,
- content = actions
- )
- }
+ val actionsRow =
+ @Composable {
+ Row(
+ horizontalArrangement = Arrangement.End,
+ verticalAlignment = Alignment.CenterVertically,
+ content = actions
+ )
+ }
// Compose a Surface with a TopAppBarLayout content.
- Surface(color = colors.scrolledContainerColor) {
+ Box(
+ modifier =
+ Modifier.drawBehind { drawRect(color = colors.scrolledContainerColor) }
+ .semantics { isTraversalGroup = true }
+ .pointerInput(Unit) {}
+ ) {
val height = LocalDensity.current.run { ContainerHeight.toPx() }
TopAppBarLayout(
- modifier = Modifier
- .windowInsetsPadding(windowInsets)
- // clip after padding so we don't show the title over the inset area
- .clipToBounds(),
+ modifier =
+ Modifier.windowInsetsPadding(windowInsets)
+ // clip after padding so we don't show the title over the inset area
+ .clipToBounds(),
heightPx = height,
navigationIconContentColor = colors.navigationIconContentColor,
titleContentColor = colors.titleContentColor,
actionIconContentColor = colors.actionIconContentColor,
title = title,
titleTextStyle = titleTextStyle,
- titleAlpha = 1f,
+ titleAlpha = { 1f },
titleVerticalArrangement = Arrangement.Center,
titleBottomPadding = 0,
hideTitleSemantics = false,
@@ -271,7 +280,7 @@
* composables.
*
* @throws [IllegalArgumentException] if the given [MaxHeightWithoutTitle] is equal or smaller than
- * the [pinnedHeight]
+ * the [pinnedHeight]
*/
@OptIn(ExperimentalMaterial3Api::class)
@Composable
@@ -308,62 +317,67 @@
// Sets the app bar's height offset limit to hide just the bottom title area and keep top title
// visible when collapsed.
- SideEffect {
- if (scrollBehavior?.state?.heightOffsetLimit != pinnedHeightPx - maxHeightPx.floatValue) {
- scrollBehavior?.state?.heightOffsetLimit = pinnedHeightPx - maxHeightPx.floatValue
- }
- }
+ scrollBehavior?.state?.heightOffsetLimit = pinnedHeightPx - maxHeightPx.floatValue
// Obtain the container Color from the TopAppBarColors using the `collapsedFraction`, as the
// bottom part of this TwoRowsTopAppBar changes color at the same rate the app bar expands or
// collapse.
// This will potentially animate or interpolate a transition between the container color and the
// container's scrolled color according to the app bar's scroll state.
- val colorTransitionFraction = scrollBehavior?.state?.collapsedFraction ?: 0f
- val appBarContainerColor = colors.containerColor(colorTransitionFraction)
+ val colorTransitionFraction = { scrollBehavior?.state?.collapsedFraction ?: 0f }
+ val appBarContainerColor = { colors.containerColor(colorTransitionFraction()) }
// Wrap the given actions in a Row.
- val actionsRow = @Composable {
- Row(
- horizontalArrangement = Arrangement.End,
- verticalAlignment = Alignment.CenterVertically,
- content = actions
- )
- }
- val topTitleAlpha = TopTitleAlphaEasing.transform(colorTransitionFraction)
- val bottomTitleAlpha = 1f - colorTransitionFraction
+ val actionsRow =
+ @Composable {
+ Row(
+ horizontalArrangement = Arrangement.End,
+ verticalAlignment = Alignment.CenterVertically,
+ content = actions
+ )
+ }
+ val topTitleAlpha = { TopTitleAlphaEasing.transform(colorTransitionFraction()) }
+ val bottomTitleAlpha = { 1f - colorTransitionFraction() }
// Hide the top row title semantics when its alpha value goes below 0.5 threshold.
// Hide the bottom row title semantics when the top title semantics are active.
- val hideTopRowSemantics = colorTransitionFraction < 0.5f
+ val hideTopRowSemantics by
+ remember(colorTransitionFraction) { derivedStateOf { colorTransitionFraction() < 0.5f } }
val hideBottomRowSemantics = !hideTopRowSemantics
// Set up support for resizing the top app bar when vertically dragging the bar itself.
- val appBarDragModifier = if (scrollBehavior != null && !scrollBehavior.isPinned) {
- Modifier.draggable(
- orientation = Orientation.Vertical,
- state = rememberDraggableState { delta ->
- scrollBehavior.state.heightOffset += delta
- },
- onDragStopped = { velocity ->
- settleAppBar(
- scrollBehavior.state,
- velocity,
- scrollBehavior.flingAnimationSpec,
- scrollBehavior.snapAnimationSpec
- )
- }
- )
- } else {
- Modifier
- }
+ val appBarDragModifier =
+ if (scrollBehavior != null && !scrollBehavior.isPinned) {
+ Modifier.draggable(
+ orientation = Orientation.Vertical,
+ state =
+ rememberDraggableState { delta -> scrollBehavior.state.heightOffset += delta },
+ onDragStopped = { velocity ->
+ settleAppBar(
+ scrollBehavior.state,
+ velocity,
+ scrollBehavior.flingAnimationSpec,
+ scrollBehavior.snapAnimationSpec
+ )
+ }
+ )
+ } else {
+ Modifier
+ }
- Surface(modifier = modifier.then(appBarDragModifier), color = appBarContainerColor) {
+ Box(
+ modifier =
+ modifier
+ .then(appBarDragModifier)
+ .drawBehind { drawRect(color = appBarContainerColor()) }
+ .semantics { isTraversalGroup = true }
+ .pointerInput(Unit) {}
+ ) {
Column {
TopAppBarLayout(
- modifier = Modifier
- .windowInsetsPadding(windowInsets)
- // clip after padding so we don't show the title over the inset area
- .clipToBounds(),
+ modifier =
+ Modifier.windowInsetsPadding(windowInsets)
+ // clip after padding so we don't show the title over the inset area
+ .clipToBounds(),
heightPx = pinnedHeightPx,
navigationIconContentColor = colors.navigationIconContentColor,
titleContentColor = colors.titleContentColor,
@@ -378,27 +392,37 @@
actions = actionsRow,
)
TopAppBarLayout(
- modifier = Modifier
- // only apply the horizontal sides of the window insets padding, since the top
- // padding will always be applied by the layout above
- .windowInsetsPadding(windowInsets.only(WindowInsetsSides.Horizontal))
- .clipToBounds(),
- heightPx = maxHeightPx.floatValue - pinnedHeightPx +
- (scrollBehavior?.state?.heightOffset ?: 0f),
+ modifier =
+ Modifier
+ // only apply the horizontal sides of the window insets padding, since the
+ // top
+ // padding will always be applied by the layout above
+ .windowInsetsPadding(windowInsets.only(WindowInsetsSides.Horizontal))
+ .clipToBounds(),
+ heightPx =
+ maxHeightPx.floatValue - pinnedHeightPx +
+ (scrollBehavior?.state?.heightOffset ?: 0f),
navigationIconContentColor = colors.navigationIconContentColor,
titleContentColor = colors.titleContentColor,
actionIconContentColor = colors.actionIconContentColor,
title = {
- Box(modifier = Modifier.onGloballyPositioned { coordinates ->
- val measuredMaxHeightPx = density.run {
- MaxHeightWithoutTitle.toPx() + coordinates.size.height.toFloat()
- }
- // Allow larger max height for multi-line title, but do not reduce
- // max height to prevent flaky.
- if (measuredMaxHeightPx > defaultMaxHeightPx) {
- maxHeightPx.floatValue = measuredMaxHeightPx
- }
- }) { title() }
+ Box(
+ modifier =
+ Modifier.onGloballyPositioned { coordinates ->
+ val measuredMaxHeightPx =
+ density.run {
+ MaxHeightWithoutTitle.toPx() +
+ coordinates.size.height.toFloat()
+ }
+ // Allow larger max height for multi-line title, but do not reduce
+ // max height to prevent flaky.
+ if (measuredMaxHeightPx > defaultMaxHeightPx) {
+ maxHeightPx.floatValue = measuredMaxHeightPx
+ }
+ }
+ ) {
+ title()
+ }
},
titleTextStyle = titleTextStyle,
titleAlpha = bottomTitleAlpha,
@@ -420,21 +444,21 @@
* @param modifier a [Modifier]
* @param heightPx the total height this layout is capped to
* @param navigationIconContentColor the content color that will be applied via a
- * [LocalContentColor] when composing the navigation icon
+ * [LocalContentColor] when composing the navigation icon
* @param titleContentColor the color that will be applied via a [LocalContentColor] when composing
- * the title
+ * the title
* @param actionIconContentColor the content color that will be applied via a [LocalContentColor]
- * when composing the action icons
+ * when composing the action icons
* @param title the top app bar title (header)
* @param titleTextStyle the title's text style
* @param modifier a [Modifier]
* @param titleAlpha the title's alpha
* @param titleVerticalArrangement the title's vertical arrangement
* @param titleBottomPadding the title's bottom padding
- * @param hideTitleSemantics hides the title node from the semantic tree. Apply this
- * boolean when this layout is part of a [TwoRowsTopAppBar] to hide the title's semantics
- * from accessibility services. This is needed to avoid having multiple titles visible to
- * accessibility services at the same time, when animating between collapsed / expanded states.
+ * @param hideTitleSemantics hides the title node from the semantic tree. Apply this boolean when
+ * this layout is part of a [TwoRowsTopAppBar] to hide the title's semantics from accessibility
+ * services. This is needed to avoid having multiple titles visible to accessibility services at
+ * the same time, when animating between collapsed / expanded states.
* @param navigationIcon a navigation icon [Composable]
* @param actions actions [Composable]
* @param titleScaleDisabled whether the title font scaling is disabled. Default is disabled.
@@ -448,7 +472,7 @@
actionIconContentColor: Color,
title: @Composable () -> Unit,
titleTextStyle: TextStyle,
- titleAlpha: Float,
+ titleAlpha: () -> Float,
titleVerticalArrangement: Arrangement.Vertical,
titleBottomPadding: Int,
hideTitleSemantics: Boolean,
@@ -458,41 +482,33 @@
) {
Layout(
{
- Box(
- Modifier
- .layoutId("navigationIcon")
- .padding(start = TopAppBarHorizontalPadding)
- ) {
+ Box(Modifier.layoutId("navigationIcon").padding(start = TopAppBarHorizontalPadding)) {
CompositionLocalProvider(
LocalContentColor provides navigationIconContentColor,
content = navigationIcon
)
}
Box(
- Modifier
- .layoutId("title")
+ Modifier.layoutId("title")
.padding(horizontal = TopAppBarHorizontalPadding)
- .then(if (hideTitleSemantics) Modifier.clearAndSetSemantics { } else Modifier)
- .graphicsLayer(alpha = titleAlpha)
+ .then(if (hideTitleSemantics) Modifier.clearAndSetSemantics {} else Modifier)
+ .graphicsLayer { alpha = titleAlpha() }
) {
ProvideTextStyle(value = titleTextStyle) {
CompositionLocalProvider(
LocalContentColor provides titleContentColor,
- LocalDensity provides with(LocalDensity.current) {
- Density(
- density = density,
- fontScale = if (titleScaleDisabled) 1f else fontScale,
- )
- },
+ LocalDensity provides
+ with(LocalDensity.current) {
+ Density(
+ density = density,
+ fontScale = if (titleScaleDisabled) 1f else fontScale,
+ )
+ },
content = title
)
}
}
- Box(
- Modifier
- .layoutId("actionIcons")
- .padding(end = TopAppBarHorizontalPadding)
- ) {
+ Box(Modifier.layoutId("actionIcons").padding(end = TopAppBarHorizontalPadding)) {
CompositionLocalProvider(
LocalContentColor provides actionIconContentColor,
content = actions
@@ -502,20 +518,24 @@
modifier = modifier
) { measurables, constraints ->
val navigationIconPlaceable =
- measurables.first { it.layoutId == "navigationIcon" }
+ measurables
+ .first { it.layoutId == "navigationIcon" }
.measure(constraints.copy(minWidth = 0))
val actionIconsPlaceable =
- measurables.first { it.layoutId == "actionIcons" }
+ measurables
+ .first { it.layoutId == "actionIcons" }
.measure(constraints.copy(minWidth = 0))
- val maxTitleWidth = if (constraints.maxWidth == Constraints.Infinity) {
- constraints.maxWidth
- } else {
- (constraints.maxWidth - navigationIconPlaceable.width - actionIconsPlaceable.width)
- .coerceAtLeast(0)
- }
+ val maxTitleWidth =
+ if (constraints.maxWidth == Constraints.Infinity) {
+ constraints.maxWidth
+ } else {
+ (constraints.maxWidth - navigationIconPlaceable.width - actionIconsPlaceable.width)
+ .coerceAtLeast(0)
+ }
val titlePlaceable =
- measurables.first { it.layoutId == "title" }
+ measurables
+ .first { it.layoutId == "title" }
.measure(constraints.copy(minWidth = 0, maxWidth = maxTitleWidth))
// Locate the title's baseline.
@@ -538,19 +558,23 @@
// Title
titlePlaceable.placeRelative(
x = max(TopAppBarTitleInset.roundToPx(), navigationIconPlaceable.width),
- y = when (titleVerticalArrangement) {
- Arrangement.Center -> (layoutHeight - titlePlaceable.height) / 2
- // Apply bottom padding from the title's baseline only when the Arrangement is
- // "Bottom".
- Arrangement.Bottom ->
- if (titleBottomPadding == 0) layoutHeight - titlePlaceable.height
- else layoutHeight - titlePlaceable.height - max(
- 0,
- titleBottomPadding - titlePlaceable.height + titleBaseline
- )
- // Arrangement.Top
- else -> 0
- }
+ y =
+ when (titleVerticalArrangement) {
+ Arrangement.Center -> (layoutHeight - titlePlaceable.height) / 2
+ // Apply bottom padding from the title's baseline only when the Arrangement
+ // is "Bottom".
+ Arrangement.Bottom ->
+ if (titleBottomPadding == 0) layoutHeight - titlePlaceable.height
+ else
+ layoutHeight -
+ titlePlaceable.height -
+ max(
+ 0,
+ titleBottomPadding - titlePlaceable.height + titleBaseline
+ )
+ // Arrangement.Top
+ else -> 0
+ }
)
// Action icons
@@ -562,7 +586,6 @@
}
}
-
/**
* Settles the app bar by flinging, in case the given velocity is greater than zero, and snapping
* after the fling settles.
@@ -587,9 +610,9 @@
if (flingAnimationSpec != null && abs(velocity) > 1f) {
var lastValue = 0f
AnimationState(
- initialValue = 0f,
- initialVelocity = velocity,
- )
+ initialValue = 0f,
+ initialVelocity = velocity,
+ )
.animateDecay(flingAnimationSpec) {
val delta = value - lastValue
val initialHeightOffset = state.heightOffset
@@ -603,9 +626,7 @@
}
// Snap if animation specs were provided.
if (snapAnimationSpec != null) {
- if (state.heightOffset < 0 &&
- state.heightOffset > state.heightOffsetLimit
- ) {
+ if (state.heightOffset < 0 && state.heightOffset > state.heightOffsetLimit) {
AnimationState(initialValue = state.heightOffset).animateTo(
if (state.collapsedFraction < 0.5f) {
0f
@@ -613,7 +634,9 @@
state.heightOffsetLimit
},
animationSpec = snapAnimationSpec
- ) { state.heightOffset = value }
+ ) {
+ state.heightOffset = value
+ }
}
}
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBarTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBarTest.kt
index ea69eab..0a4f0d9 100644
--- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBarTest.kt
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBarTest.kt
@@ -37,15 +37,11 @@
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.painter.ColorPainter
import androidx.compose.ui.input.nestedscroll.nestedScroll
-import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.test.assertHeightIsEqualTo
import androidx.compose.ui.test.assertIsDisplayed
-import androidx.compose.ui.test.assertLeftPositionInRootIsEqualTo
-import androidx.compose.ui.test.assertTopPositionInRootIsEqualTo
import androidx.compose.ui.test.assertWidthIsEqualTo
-import androidx.compose.ui.test.getUnclippedBoundsInRoot
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.onNodeWithText
@@ -53,33 +49,24 @@
import androidx.compose.ui.test.swipeLeft
import androidx.compose.ui.test.swipeRight
import androidx.compose.ui.text.TextStyle
-import androidx.compose.ui.unit.Dp
-import androidx.compose.ui.unit.dp
-import androidx.compose.ui.unit.height
-import androidx.compose.ui.unit.width
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settingslib.spa.testutils.rootWidth
import com.android.settingslib.spa.testutils.setContentForSizeAssertions
import com.google.common.truth.Truth.assertThat
-import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@OptIn(ExperimentalMaterial3Api::class)
-@Ignore("b/346785755")
@RunWith(AndroidJUnit4::class)
class CustomizedAppBarTest {
- @get:Rule
- val rule = createComposeRule()
+ @get:Rule val rule = createComposeRule()
@Test
fun smallTopAppBar_expandsToScreen() {
rule
- .setContentForSizeAssertions {
- CustomizedTopAppBar(title = { Text("Title") })
- }
+ .setContentForSizeAssertions { CustomizedTopAppBar(title = { Text("Title") }) }
.assertHeightIsEqualTo(ContainerHeight)
.assertWidthIsEqualTo(rule.rootWidth())
}
@@ -88,51 +75,12 @@
fun smallTopAppBar_withTitle() {
val title = "Title"
rule.setContent {
- Box(Modifier.testTag(TopAppBarTestTag)) {
- CustomizedTopAppBar(title = { Text(title) })
- }
+ Box(Modifier.testTag(TopAppBarTestTag)) { CustomizedTopAppBar(title = { Text(title) }) }
}
rule.onNodeWithText(title).assertIsDisplayed()
}
@Test
- fun smallTopAppBar_default_positioning() {
- rule.setContent {
- Box(Modifier.testTag(TopAppBarTestTag)) {
- CustomizedTopAppBar(
- navigationIcon = {
- FakeIcon(Modifier.testTag(NavigationIconTestTag))
- },
- title = {
- Text("Title", Modifier.testTag(TitleTestTag))
- },
- actions = {
- FakeIcon(Modifier.testTag(ActionsTestTag))
- }
- )
- }
- }
- assertSmallDefaultPositioning()
- }
-
- @Test
- fun smallTopAppBar_noNavigationIcon_positioning() {
- rule.setContent {
- Box(Modifier.testTag(TopAppBarTestTag)) {
- CustomizedTopAppBar(
- title = {
- Text("Title", Modifier.testTag(TitleTestTag))
- },
- actions = {
- FakeIcon(Modifier.testTag(ActionsTestTag))
- }
- )
- }
- }
- assertSmallPositioningWithoutNavigation()
- }
-
- @Test
fun smallTopAppBar_titleDefaultStyle() {
var textStyle: TextStyle? = null
var expectedTextStyle: TextStyle? = null
@@ -188,29 +136,6 @@
assertThat(actionsColor).isEqualTo(expectedActionsColor)
}
- @Test
- fun largeTopAppBar_scrolled_positioning() {
- val content = @Composable { scrollBehavior: TopAppBarScrollBehavior? ->
- Box(Modifier.testTag(TopAppBarTestTag)) {
- CustomizedLargeTopAppBar(
- navigationIcon = {
- FakeIcon(Modifier.testTag(NavigationIconTestTag))
- },
- title = "Title",
- actions = {
- FakeIcon(Modifier.testTag(ActionsTestTag))
- },
- scrollBehavior = scrollBehavior,
- )
- }
- }
- assertLargeScrolledHeight(
- MaxHeightWithoutTitle + DefaultTitleHeight,
- MaxHeightWithoutTitle + DefaultTitleHeight,
- content,
- )
- }
-
@OptIn(ExperimentalMaterial3Api::class)
@Test
fun topAppBar_enterAlways_allowHorizontalScroll() {
@@ -221,14 +146,10 @@
}
rule.onNodeWithTag(LazyListTag).performTouchInput { swipeLeft() }
- rule.runOnIdle {
- assertThat(state.firstVisibleItemIndex).isEqualTo(1)
- }
+ rule.runOnIdle { assertThat(state.firstVisibleItemIndex).isEqualTo(1) }
rule.onNodeWithTag(LazyListTag).performTouchInput { swipeRight() }
- rule.runOnIdle {
- assertThat(state.firstVisibleItemIndex).isEqualTo(0)
- }
+ rule.runOnIdle { assertThat(state.firstVisibleItemIndex).isEqualTo(0) }
}
@OptIn(ExperimentalMaterial3Api::class)
@@ -241,14 +162,10 @@
}
rule.onNodeWithTag(LazyListTag).performTouchInput { swipeLeft() }
- rule.runOnIdle {
- assertThat(state.firstVisibleItemIndex).isEqualTo(1)
- }
+ rule.runOnIdle { assertThat(state.firstVisibleItemIndex).isEqualTo(1) }
rule.onNodeWithTag(LazyListTag).performTouchInput { swipeRight() }
- rule.runOnIdle {
- assertThat(state.firstVisibleItemIndex).isEqualTo(0)
- }
+ rule.runOnIdle { assertThat(state.firstVisibleItemIndex).isEqualTo(0) }
}
@OptIn(ExperimentalMaterial3Api::class)
@@ -257,21 +174,14 @@
lateinit var state: LazyListState
rule.setContent {
state = rememberLazyListState()
- MultiPageContent(
- TopAppBarDefaults.pinnedScrollBehavior(),
- state
- )
+ MultiPageContent(TopAppBarDefaults.pinnedScrollBehavior(), state)
}
rule.onNodeWithTag(LazyListTag).performTouchInput { swipeLeft() }
- rule.runOnIdle {
- assertThat(state.firstVisibleItemIndex).isEqualTo(1)
- }
+ rule.runOnIdle { assertThat(state.firstVisibleItemIndex).isEqualTo(1) }
rule.onNodeWithTag(LazyListTag).performTouchInput { swipeRight() }
- rule.runOnIdle {
- assertThat(state.firstVisibleItemIndex).isEqualTo(0)
- }
+ rule.runOnIdle { assertThat(state.firstVisibleItemIndex).isEqualTo(0) }
}
@OptIn(ExperimentalMaterial3Api::class)
@@ -285,11 +195,7 @@
)
}
) { contentPadding ->
- LazyRow(
- Modifier
- .fillMaxSize()
- .testTag(LazyListTag), state
- ) {
+ LazyRow(Modifier.fillMaxSize().testTag(LazyListTag), state) {
items(2) { page ->
LazyColumn(
modifier = Modifier.fillParentMaxSize(),
@@ -308,146 +214,19 @@
}
/**
- * Checks the app bar's components positioning when it's a [CustomizedTopAppBar]
- * or a larger app bar that is scrolled up and collapsed into a small
- * configuration and there is no navigation icon.
- */
- private fun assertSmallPositioningWithoutNavigation(isCenteredTitle: Boolean = false) {
- val appBarBounds = rule.onNodeWithTag(TopAppBarTestTag).getUnclippedBoundsInRoot()
- val titleBounds = rule.onNodeWithTag(TitleTestTag).getUnclippedBoundsInRoot()
-
- val titleNode = rule.onNodeWithTag(TitleTestTag)
- // Title should be vertically centered
- titleNode.assertTopPositionInRootIsEqualTo((appBarBounds.height - titleBounds.height) / 2)
- if (isCenteredTitle) {
- // Title should be horizontally centered
- titleNode.assertLeftPositionInRootIsEqualTo(
- (appBarBounds.width - titleBounds.width) / 2
- )
- } else {
- // Title should now be placed 16.dp from the start, as there is no navigation icon
- // 4.dp padding for the whole app bar + 12.dp inset
- titleNode.assertLeftPositionInRootIsEqualTo(4.dp + 12.dp)
- }
-
- rule.onNodeWithTag(ActionsTestTag)
- // Action should still be placed at the end
- .assertLeftPositionInRootIsEqualTo(expectedActionPosition(appBarBounds.width))
- }
-
- /**
- * Checks the app bar's components positioning when it's a [CustomizedTopAppBar].
- */
- private fun assertSmallDefaultPositioning(isCenteredTitle: Boolean = false) {
- val appBarBounds = rule.onNodeWithTag(TopAppBarTestTag).getUnclippedBoundsInRoot()
- val titleBounds = rule.onNodeWithTag(TitleTestTag).getUnclippedBoundsInRoot()
- val appBarBottomEdgeY = appBarBounds.top + appBarBounds.height
-
- rule.onNodeWithTag(NavigationIconTestTag)
- // Navigation icon should be 4.dp from the start
- .assertLeftPositionInRootIsEqualTo(AppBarStartAndEndPadding)
- // Navigation icon should be centered within the height of the app bar.
- .assertTopPositionInRootIsEqualTo(
- appBarBottomEdgeY - AppBarTopAndBottomPadding - FakeIconSize
- )
-
- val titleNode = rule.onNodeWithTag(TitleTestTag)
- // Title should be vertically centered
- titleNode.assertTopPositionInRootIsEqualTo((appBarBounds.height - titleBounds.height) / 2)
- if (isCenteredTitle) {
- // Title should be horizontally centered
- titleNode.assertLeftPositionInRootIsEqualTo(
- (appBarBounds.width - titleBounds.width) / 2
- )
- } else {
- // Title should be 56.dp from the start
- // 4.dp padding for the whole app bar + 48.dp icon size + 4.dp title padding.
- titleNode.assertLeftPositionInRootIsEqualTo(4.dp + FakeIconSize + 4.dp)
- }
-
- rule.onNodeWithTag(ActionsTestTag)
- // Action should be placed at the end
- .assertLeftPositionInRootIsEqualTo(expectedActionPosition(appBarBounds.width))
- // Action should be 8.dp from the top
- .assertTopPositionInRootIsEqualTo(
- appBarBottomEdgeY - AppBarTopAndBottomPadding - FakeIconSize
- )
- }
-
- /**
- * Checks that changing values at a [CustomizedLargeTopAppBar] scroll behavior
- * affects the height of the app bar.
- *
- * This check partially and fully collapses the app bar to test its height.
- *
- * @param appBarMaxHeight the max height of the app bar [content]
- * @param appBarMinHeight the min height of the app bar [content]
- * @param content a Composable that adds a CustomizedLargeTopAppBar
- */
- @OptIn(ExperimentalMaterial3Api::class)
- private fun assertLargeScrolledHeight(
- appBarMaxHeight: Dp,
- appBarMinHeight: Dp,
- content: @Composable (TopAppBarScrollBehavior?) -> Unit
- ) {
- val fullyCollapsedOffsetDp = appBarMaxHeight - appBarMinHeight
- val partiallyCollapsedOffsetDp = fullyCollapsedOffsetDp / 3
- var partiallyCollapsedHeightOffsetPx = 0f
- var fullyCollapsedHeightOffsetPx = 0f
- lateinit var scrollBehavior: TopAppBarScrollBehavior
- rule.setContent {
- scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior()
- with(LocalDensity.current) {
- partiallyCollapsedHeightOffsetPx = partiallyCollapsedOffsetDp.toPx()
- fullyCollapsedHeightOffsetPx = fullyCollapsedOffsetDp.toPx()
- }
-
- content(scrollBehavior)
- }
-
- // Simulate a partially collapsed app bar.
- rule.runOnIdle {
- scrollBehavior.state.heightOffset = -partiallyCollapsedHeightOffsetPx
- scrollBehavior.state.contentOffset = -partiallyCollapsedHeightOffsetPx
- }
- rule.waitForIdle()
- rule.onNodeWithTag(TopAppBarTestTag)
- .assertHeightIsEqualTo(
- appBarMaxHeight - partiallyCollapsedOffsetDp
- )
-
- // Simulate a fully collapsed app bar.
- rule.runOnIdle {
- scrollBehavior.state.heightOffset = -fullyCollapsedHeightOffsetPx
- // Simulate additional content scroll beyond the max offset scroll.
- scrollBehavior.state.contentOffset =
- -fullyCollapsedHeightOffsetPx - partiallyCollapsedHeightOffsetPx
- }
- rule.waitForIdle()
- // Check that the app bar collapsed to its min height.
- rule.onNodeWithTag(TopAppBarTestTag).assertHeightIsEqualTo(appBarMinHeight)
- }
-
- /**
* An [IconButton] with an [Icon] inside for testing positions.
*
* An [IconButton] is defaulted to be 48X48dp, while its child [Icon] is defaulted to 24x24dp.
*/
- private val FakeIcon = @Composable { modifier: Modifier ->
- IconButton(
- onClick = { /* doSomething() */ },
- modifier = modifier.semantics(mergeDescendants = true) {}
- ) {
- Icon(ColorPainter(Color.Red), null)
+ private val FakeIcon =
+ @Composable { modifier: Modifier ->
+ IconButton(
+ onClick = { /* doSomething() */ },
+ modifier = modifier.semantics(mergeDescendants = true) {}
+ ) {
+ Icon(ColorPainter(Color.Red), null)
+ }
}
- }
-
- private fun expectedActionPosition(appBarWidth: Dp): Dp =
- appBarWidth - AppBarStartAndEndPadding - FakeIconSize
-
- private val FakeIconSize = 48.dp
- private val AppBarStartAndEndPadding = 4.dp
- private val AppBarTopAndBottomPadding = (ContainerHeight - FakeIconSize) / 2
private val LazyListTag = "lazyList"
private val TopAppBarTestTag = "bar"
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/compose/DisposableBroadcastReceiverAsUserTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/compose/DisposableBroadcastReceiverAsUserTest.kt
index dd7c036..a59a724 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/compose/DisposableBroadcastReceiverAsUserTest.kt
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/compose/DisposableBroadcastReceiverAsUserTest.kt
@@ -23,8 +23,8 @@
import android.os.UserHandle
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.platform.LocalContext
-import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.lifecycle.compose.LocalLifecycleOwner
import androidx.lifecycle.testing.TestLifecycleOwner
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Rule
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt
index c60ce41..b1baa86 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt
@@ -31,6 +31,8 @@
import android.os.BadParcelableException
import android.os.DeadObjectException
import android.os.UserManager
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
import android.platform.test.flag.junit.SetFlagsRule
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -76,9 +78,7 @@
}
private val mockUserManager = mock<UserManager> {
- on { getUserInfo(ADMIN_USER_ID) } doReturn UserInfo().apply {
- flags = UserInfo.FLAG_ADMIN
- }
+ on { getUserInfo(ADMIN_USER_ID) } doReturn UserInfo(0, "admin", UserInfo.FLAG_ADMIN)
on { getProfileIdsWithDisabled(ADMIN_USER_ID) } doReturn
intArrayOf(ADMIN_USER_ID, MANAGED_PROFILE_USER_ID)
}
@@ -281,9 +281,9 @@
)
}
+ @EnableFlags(Flags.FLAG_PROVIDE_INFO_OF_APK_IN_APEX)
@Test
fun loadApps_hasApkInApexInfo_shouldNotIncludeAllHiddenApps() = runTest {
- mSetFlagsRule.enableFlags(Flags.FLAG_PROVIDE_INFO_OF_APK_IN_APEX)
packageManager.stub {
on { getInstalledModules(any()) } doReturn listOf(HIDDEN_MODULE)
}
@@ -297,9 +297,9 @@
assertThat(appList).containsExactly(NORMAL_APP)
}
+ @DisableFlags(Flags.FLAG_PROVIDE_INFO_OF_APK_IN_APEX)
@Test
fun loadApps_noApkInApexInfo_shouldNotIncludeHiddenSystemModule() = runTest {
- mSetFlagsRule.disableFlags(Flags.FLAG_PROVIDE_INFO_OF_APK_IN_APEX)
packageManager.stub {
on { getInstalledModules(any()) } doReturn listOf(HIDDEN_MODULE)
}
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index 50f0c2e..9da1d60 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -236,7 +236,7 @@
</string-array>
<string name="choose_profile" msgid="343803890897657450">"Pilih profil"</string>
<string name="category_personal" msgid="6236798763159385225">"Peribadi"</string>
- <string name="category_work" msgid="4014193632325996115">"Tempat Kerja"</string>
+ <string name="category_work" msgid="4014193632325996115">"Kerja"</string>
<string name="category_private" msgid="4244892185452788977">"Persendirian"</string>
<string name="category_clone" msgid="1554511758987195974">"Klon"</string>
<string name="development_settings_title" msgid="140296922921597393">"Pilihan pembangun"</string>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 363045e..d373201 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -953,6 +953,18 @@
<string name="enable_verbose_vendor_logging">Enable verbose vendor logging</string>
<!-- UI debug setting: enable verbose vendor logging summary [CHAR LIMIT=NONE] -->
<string name="enable_verbose_vendor_logging_summary">Include additional device-specific vendor logs in bug reports, which may contain private information, use more battery, and/or use more storage.</string>
+ <!-- UI debug setting: checkbox text to disable verbose vendor logging after one day [CHAR LIMIT=50] -->
+ <string name="enable_verbose_vendor_logging_checkbox">Disable after one day</string>
+ <!-- UI debug setting: verbose vendor logging notification title [CHAR LIMIT=60] -->
+ <string name="verbose_vendor_logging_notification_title">Verbose vendor logging has ended</string>
+ <!-- UI debug setting: verbose vendor logging notification summary [CHAR LIMIT=60] -->
+ <string name="verbose_vendor_logging_notification_summary">Enabled for one day</string>
+ <!-- UI debug setting: verbose vendor logging notification action text [CHAR LIMIT=60] -->
+ <string name="verbose_vendor_logging_notification_action">Enable for one more day</string>
+ <!-- UI debug setting: verbose vendor logging preference summary for disabling after one day [CHAR LIMIT=60] -->
+ <string name="verbose_vendor_logging_preference_summary_will_disable">Disables after one day</string>
+ <!-- UI debug setting: verbose vendor logging preference summary for leaving setting enabled indefinitely [CHAR LIMIT=60] -->
+ <string name="verbose_vendor_logging_preference_summary_on">Enabled indefinitely</string>
<!-- UI debug setting: scaling factor for window animations [CHAR LIMIT=25] -->
<string name="window_animation_scale_title">Window animation scale</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
index b7758de..4e1d8e3 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
@@ -671,7 +671,7 @@
// MediaRoute2Info.getType was made public on API 34, but exists since API 30.
@SuppressWarnings("NewApi")
@VisibleForTesting
- void addMediaDevice(MediaRoute2Info route, RoutingSessionInfo activeSession) {
+ void addMediaDevice(@NonNull MediaRoute2Info route, @NonNull RoutingSessionInfo activeSession) {
final int deviceType = route.getType();
MediaDevice mediaDevice = null;
switch (deviceType) {
@@ -711,8 +711,13 @@
case TYPE_HEARING_AID:
case TYPE_BLUETOOTH_A2DP:
case TYPE_BLE_HEADSET:
+ if (route.getAddress() == null) {
+ Log.e(TAG, "Ignoring bluetooth route with no set address: " + route);
+ break;
+ }
final BluetoothDevice device =
- BluetoothAdapter.getDefaultAdapter().getRemoteDevice(route.getAddress());
+ BluetoothAdapter.getDefaultAdapter()
+ .getRemoteDevice(route.getAddress());
final CachedBluetoothDevice cachedDevice =
mBluetoothManager.getCachedDeviceManager().findDevice(device);
if (cachedDevice != null) {
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index 1cbf67e..0fdcc7a 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -884,16 +884,6 @@
}
flag {
- name: "shade_collapse_activity_launch_fix"
- namespace: "systemui"
- description: "Avoid collapsing the shade on activity launch if it is already collapsed, as this causes a flicker."
- bug: "331591373"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
name: "slice_broadcast_relay_in_background"
namespace: "systemui"
description: "Move handling of slice broadcast relay broadcasts to background threads"
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
index c4659cf..7c2f7fe 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
@@ -59,9 +59,11 @@
import com.android.systemui.communal.ui.compose.extensions.allowGestures
import com.android.systemui.communal.ui.viewmodel.CommunalViewModel
import com.android.systemui.communal.util.CommunalColors
+import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor.Companion.TO_GONE_DURATION
import com.android.systemui.res.R
import com.android.systemui.scene.shared.model.SceneDataSourceDelegator
import com.android.systemui.scene.ui.composable.SceneTransitionLayoutDataSource
+import kotlin.time.DurationUnit
object Communal {
object Elements {
@@ -91,6 +93,10 @@
spec = tween(durationMillis = 250)
fade(AllElements)
}
+ to(CommunalScenes.Blank, key = CommunalTransitionKeys.SimpleFade) {
+ spec = tween(durationMillis = TO_GONE_DURATION.toInt(DurationUnit.MILLISECONDS))
+ fade(AllElements)
+ }
to(CommunalScenes.Communal) {
spec = tween(durationMillis = 1000)
translate(Communal.Elements.Grid, Edge.Right)
@@ -226,10 +232,14 @@
scene(
CommunalScenes.Communal,
- userActions =
- mapOf(Swipe(SwipeDirection.Right, fromSource = Edge.Left) to CommunalScenes.Blank)
+ userActions = mapOf(Swipe(SwipeDirection.Right) to CommunalScenes.Blank)
) {
- CommunalScene(backgroundType, colors, content)
+ CommunalScene(
+ backgroundType = backgroundType,
+ colors = colors,
+ content = content,
+ modifier = Modifier.horizontalNestedScrollToScene(),
+ )
}
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
index 927890e..fbfe050 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
@@ -378,16 +378,6 @@
onCancel = viewModel::onEnableWorkProfileDialogCancel
)
}
-
- // This spacer covers the edge of the LazyHorizontalGrid and prevents it from receiving
- // touches, so that the SceneTransitionLayout can intercept the touches and allow an edge
- // swipe back to the blank scene.
- Spacer(
- Modifier.height(Dimensions.GridHeight)
- .align(Alignment.CenterStart)
- .width(Dimensions.Spacing)
- .pointerInput(Unit) {}
- )
}
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt
index 45a8393..29223ce 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt
@@ -28,6 +28,7 @@
import androidx.compose.foundation.layout.asPaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.systemBars
@@ -65,6 +66,7 @@
import androidx.compose.ui.util.lerp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.animation.scene.ElementKey
+import com.android.compose.animation.scene.LowestZIndexScenePicker
import com.android.compose.animation.scene.NestedScrollBehavior
import com.android.compose.animation.scene.SceneScope
import com.android.compose.modifiers.thenIf
@@ -89,7 +91,8 @@
object Elements {
val NotificationScrim = ElementKey("NotificationScrim")
val NotificationStackPlaceholder = ElementKey("NotificationStackPlaceholder")
- val HeadsUpNotificationPlaceholder = ElementKey("HeadsUpNotificationPlaceholder")
+ val HeadsUpNotificationPlaceholder =
+ ElementKey("HeadsUpNotificationPlaceholder", scenePicker = LowestZIndexScenePicker)
val ShelfSpace = ElementKey("ShelfSpace")
}
@@ -112,10 +115,10 @@
modifier: Modifier = Modifier,
isPeekFromBottom: Boolean = false,
) {
- Element(
- Notifications.Elements.HeadsUpNotificationPlaceholder,
+ Box(
modifier =
modifier
+ .element(Notifications.Elements.HeadsUpNotificationPlaceholder)
.fillMaxWidth()
.notificationHeadsUpHeight(stackScrollView)
.debugBackground(viewModel, DEBUG_HUN_COLOR)
@@ -129,9 +132,7 @@
// Note: boundsInWindow doesn't scroll off the screen
stackScrollView.setHeadsUpTop(boundsInWindow.top)
}
- ) {
- content {}
- }
+ )
}
/** Adds the space where notification stack should appear in the scene. */
@@ -155,6 +156,11 @@
viewModel = viewModel,
modifier = Modifier.align(Alignment.TopCenter),
)
+ NotificationStackCutoffGuideline(
+ stackScrollView = stackScrollView,
+ viewModel = viewModel,
+ modifier = Modifier.align(Alignment.BottomCenter),
+ )
}
}
@@ -171,6 +177,7 @@
shouldPunchHoleBehindScrim: Boolean,
shouldFillMaxSize: Boolean = true,
shouldReserveSpaceForNavBar: Boolean = true,
+ shouldIncludeHeadsUpSpace: Boolean = true,
shadeMode: ShadeMode,
modifier: Modifier = Modifier,
) {
@@ -187,8 +194,12 @@
viewModel.isCurrentGestureOverscroll.collectAsStateWithLifecycle(false)
val expansionFraction by viewModel.expandFraction.collectAsStateWithLifecycle(0f)
- val navBarHeight =
- with(density) { WindowInsets.systemBars.asPaddingValues().calculateBottomPadding().toPx() }
+ val navBarHeightPx =
+ with(density) {
+ WindowInsets.systemBars.asPaddingValues().calculateBottomPadding().toPx().toInt()
+ }
+ val bottomPaddingPx = if (shouldReserveSpaceForNavBar) navBarHeightPx else 0
+
val screenHeight = LocalRawScreenHeight.current
/**
@@ -352,14 +363,13 @@
}
.verticalScroll(scrollState)
.fillMaxWidth()
- .notificationStackHeight(
- view = stackScrollView,
- padding = if (shouldReserveSpaceForNavBar) navBarHeight.toInt() else 0
- )
+ .notificationStackHeight(view = stackScrollView, padding = bottomPaddingPx)
.onSizeChanged { size -> stackHeight.intValue = size.height },
)
}
- HeadsUpNotificationSpace(stackScrollView = stackScrollView, viewModel = viewModel)
+ if (shouldIncludeHeadsUpSpace) {
+ HeadsUpNotificationSpace(stackScrollView = stackScrollView, viewModel = viewModel)
+ }
}
}
@@ -395,6 +405,26 @@
)
}
+/**
+ * A 0 height horizontal spacer to be placed at the bottom-most position in the current scene, where
+ * the notification contents (stack, footer, shelf) should be drawn.
+ */
+@Composable
+fun NotificationStackCutoffGuideline(
+ stackScrollView: NotificationScrollView,
+ viewModel: NotificationsPlaceholderViewModel,
+ modifier: Modifier = Modifier,
+) {
+ Spacer(
+ modifier =
+ modifier.fillMaxWidth().height(0.dp).onGloballyPositioned { coordinates ->
+ val positionY = coordinates.positionInWindow().y
+ debugLog(viewModel) { "STACK cutoff onGloballyPositioned: y=$positionY" }
+ stackScrollView.setStackCutoff(positionY)
+ }
+ )
+}
+
@Composable
private fun SceneScope.NotificationPlaceholder(
stackScrollView: NotificationScrollView,
@@ -417,7 +447,6 @@
}
// NOTE: positionInWindow.y scrolls off screen, but boundsInWindow.top will not
stackScrollView.setStackTop(positionInWindow.y)
- stackScrollView.setStackBottom(positionInWindow.y + coordinates.size.height)
}
)
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeScene.kt
index f62a28c..899b256 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeScene.kt
@@ -20,7 +20,6 @@
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
-import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.android.compose.animation.scene.SceneScope
@@ -75,7 +74,6 @@
OverlayShade(
modifier = modifier,
viewModel = overlayShadeViewModel,
- panelAlignment = Alignment.TopEnd,
lockscreenContent = lockscreenContent,
) {
Column {
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
index 1b49b67..0b57151 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
@@ -42,6 +42,8 @@
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.navigationBars
+import androidx.compose.foundation.layout.navigationBarsPadding
+import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.rememberScrollState
@@ -62,6 +64,7 @@
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.res.colorResource
+import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.animation.scene.SceneScope
@@ -82,6 +85,8 @@
import com.android.systemui.media.controls.ui.view.MediaHost
import com.android.systemui.media.dagger.MediaModule
import com.android.systemui.notifications.ui.composable.HeadsUpNotificationSpace
+import com.android.systemui.notifications.ui.composable.NotificationScrollingStack
+import com.android.systemui.notifications.ui.composable.NotificationStackCutoffGuideline
import com.android.systemui.qs.footer.ui.compose.FooterActionsWithAnimatedVisibility
import com.android.systemui.qs.ui.composable.QuickSettings.SharedValues.MediaLandscapeTopOffset
import com.android.systemui.qs.ui.composable.QuickSettings.SharedValues.MediaOffset.InQS
@@ -90,6 +95,7 @@
import com.android.systemui.scene.session.ui.composable.SaveableSession
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.ui.composable.ComposableScene
+import com.android.systemui.shade.shared.model.ShadeMode
import com.android.systemui.shade.ui.composable.CollapsedShadeHeader
import com.android.systemui.shade.ui.composable.ExpandedShadeHeader
import com.android.systemui.shade.ui.composable.Shade
@@ -102,6 +108,7 @@
import dagger.Lazy
import javax.inject.Inject
import javax.inject.Named
+import kotlin.math.roundToInt
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.stateIn
@@ -400,5 +407,24 @@
modifier = Modifier.align(Alignment.BottomCenter),
isPeekFromBottom = true,
)
+ NotificationScrollingStack(
+ shadeSession = shadeSession,
+ stackScrollView = notificationStackScrollView,
+ viewModel = notificationsPlaceholderViewModel,
+ maxScrimTop = { screenHeight },
+ shouldPunchHoleBehindScrim = shouldPunchHoleBehindScrim,
+ shouldIncludeHeadsUpSpace = false,
+ shadeMode = ShadeMode.Single,
+ modifier =
+ Modifier.fillMaxWidth().offset { IntOffset(x = 0, y = screenHeight.roundToInt()) },
+ )
+ NotificationStackCutoffGuideline(
+ stackScrollView = notificationStackScrollView,
+ viewModel = viewModel.notifications,
+ modifier =
+ Modifier.align(Alignment.BottomCenter).navigationBarsPadding().offset {
+ IntOffset(x = 0, y = screenHeight.roundToInt())
+ }
+ )
}
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeScene.kt
index a0d6be9..4914aea 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeScene.kt
@@ -82,7 +82,6 @@
) {
OverlayShade(
viewModel = viewModel.overlayShadeViewModel,
- panelAlignment = Alignment.TopEnd,
lockscreenContent = lockscreenContent,
modifier = modifier,
) {
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt
index 5dc833b..dbf6cd3 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt
@@ -1,10 +1,12 @@
package com.android.systemui.scene.ui.composable
import androidx.compose.foundation.gestures.Orientation
+import com.android.compose.animation.scene.Edge
import com.android.compose.animation.scene.transitions
import com.android.systemui.bouncer.ui.composable.Bouncer
import com.android.systemui.notifications.ui.composable.Notifications
import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.scene.shared.model.TransitionKeys.OpenBottomShade
import com.android.systemui.scene.shared.model.TransitionKeys.SlightlyFasterShadeCollapse
import com.android.systemui.scene.shared.model.TransitionKeys.ToSplitShade
import com.android.systemui.scene.ui.composable.transitions.bouncerToGoneTransition
@@ -42,7 +44,12 @@
// Scene transitions
from(Scenes.Bouncer, to = Scenes.Gone) { bouncerToGoneTransition() }
- from(Scenes.Gone, to = Scenes.NotificationsShade) { goneToNotificationsShadeTransition() }
+ from(Scenes.Gone, to = Scenes.NotificationsShade) {
+ goneToNotificationsShadeTransition(Edge.Top)
+ }
+ from(Scenes.Gone, to = Scenes.NotificationsShade, key = OpenBottomShade) {
+ goneToNotificationsShadeTransition(Edge.Bottom)
+ }
from(Scenes.Gone, to = Scenes.Shade) { goneToShadeTransition() }
from(
Scenes.Gone,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToNotificationsShadeTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToNotificationsShadeTransition.kt
index 48ec198..fb41374 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToNotificationsShadeTransition.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToNotificationsShadeTransition.kt
@@ -16,10 +16,12 @@
package com.android.systemui.scene.ui.composable.transitions
+import com.android.compose.animation.scene.Edge
import com.android.compose.animation.scene.TransitionBuilder
fun TransitionBuilder.goneToNotificationsShadeTransition(
+ edge: Edge = Edge.Top,
durationScale: Double = 1.0,
) {
- toNotificationsShadeTransition(durationScale)
+ toNotificationsShadeTransition(edge, durationScale)
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToNotificationsShadeTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToNotificationsShadeTransition.kt
index 372e4a1a..02664c1 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToNotificationsShadeTransition.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToNotificationsShadeTransition.kt
@@ -21,5 +21,5 @@
fun TransitionBuilder.lockscreenToNotificationsShadeTransition(
durationScale: Double = 1.0,
) {
- toNotificationsShadeTransition(durationScale)
+ toNotificationsShadeTransition(durationScale = durationScale)
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToNotificationsShadeTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToNotificationsShadeTransition.kt
index 6b3b760..05949b2 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToNotificationsShadeTransition.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToNotificationsShadeTransition.kt
@@ -32,6 +32,11 @@
import kotlin.time.Duration.Companion.milliseconds
fun TransitionBuilder.toNotificationsShadeTransition(
+ /**
+ * The edge where the shade will animate from. This is statically determined (i.e. doesn't
+ * change during runtime).
+ */
+ edge: Edge = Edge.Top,
durationScale: Double = 1.0,
) {
spec = tween(durationMillis = (DefaultDuration * durationScale).inWholeMilliseconds.toInt())
@@ -50,7 +55,7 @@
}
}
- translate(OverlayShade.Elements.Panel, Edge.Top)
+ translate(OverlayShade.Elements.Panel, edge)
fractionRange(end = .5f) { fade(OverlayShade.Elements.Scrim) }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt
index c189d73..a94ebc8 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt
@@ -54,6 +54,7 @@
import com.android.compose.windowsizeclass.LocalWindowSizeClass
import com.android.systemui.keyguard.ui.composable.LockscreenContent
import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.shade.shared.model.ShadeAlignment
import com.android.systemui.shade.ui.viewmodel.OverlayShadeViewModel
import com.android.systemui.util.kotlin.getOrNull
import dagger.Lazy
@@ -63,7 +64,6 @@
@Composable
fun SceneScope.OverlayShade(
viewModel: OverlayShadeViewModel,
- panelAlignment: Alignment,
lockscreenContent: Lazy<Optional<LockscreenContent>>,
modifier: Modifier = Modifier,
content: @Composable () -> Unit,
@@ -82,7 +82,12 @@
Box(
modifier = Modifier.fillMaxSize().panelPadding(),
- contentAlignment = panelAlignment,
+ contentAlignment =
+ if (viewModel.panelAlignment == ShadeAlignment.Top) {
+ Alignment.TopEnd
+ } else {
+ Alignment.BottomEnd
+ },
) {
Panel(
modifier = Modifier.element(OverlayShade.Elements.Panel).panelSize(),
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
index ec81e23..edef5fb 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
@@ -35,6 +35,7 @@
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.navigationBars
+import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
@@ -82,6 +83,7 @@
import com.android.systemui.media.controls.ui.view.MediaHostState
import com.android.systemui.media.dagger.MediaModule.QUICK_QS_PANEL
import com.android.systemui.notifications.ui.composable.NotificationScrollingStack
+import com.android.systemui.notifications.ui.composable.NotificationStackCutoffGuideline
import com.android.systemui.qs.footer.ui.compose.FooterActionsWithAnimatedVisibility
import com.android.systemui.qs.ui.composable.BrightnessMirror
import com.android.systemui.qs.ui.composable.QSMediaMeasurePolicy
@@ -350,6 +352,11 @@
notificationsPlaceable.placeRelative(x = 0, y = maxNotifScrimTop.value.roundToInt())
}
}
+ NotificationStackCutoffGuideline(
+ stackScrollView = notificationStackScrollView,
+ viewModel = viewModel.notifications,
+ modifier = Modifier.align(Alignment.BottomCenter).navigationBarsPadding()
+ )
}
}
@@ -529,6 +536,7 @@
viewModel = viewModel.notifications,
maxScrimTop = { 0f },
shouldPunchHoleBehindScrim = false,
+ shouldReserveSpaceForNavBar = false,
shadeMode = ShadeMode.Split,
modifier =
Modifier.weight(1f)
@@ -538,5 +546,10 @@
)
}
}
+ NotificationStackCutoffGuideline(
+ stackScrollView = notificationStackScrollView,
+ viewModel = viewModel.notifications,
+ modifier = Modifier.align(Alignment.BottomCenter).navigationBarsPadding()
+ )
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractorTest.kt
index 6e48b99..43293c7 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractorTest.kt
@@ -83,24 +83,27 @@
}
@Test
- fun snapToSceneForActivity() =
+ fun changeSceneForActivityStartOnDismissKeyguard() =
testScope.runTest {
val currentScene by collectLastValue(underTest.currentScene)
- assertThat(currentScene).isEqualTo(CommunalScenes.Blank)
-
- underTest.snapToSceneForActivityStart(CommunalScenes.Communal)
+ underTest.snapToScene(CommunalScenes.Communal)
assertThat(currentScene).isEqualTo(CommunalScenes.Communal)
+
+ underTest.changeSceneForActivityStartOnDismissKeyguard()
+ assertThat(currentScene).isEqualTo(CommunalScenes.Blank)
}
@Test
- fun snapToSceneForActivity_willNotChangeScene_forEditModeActivity() =
+ fun changeSceneForActivityStartOnDismissKeyguard_willNotChangeScene_forEditModeActivity() =
testScope.runTest {
val currentScene by collectLastValue(underTest.currentScene)
- assertThat(currentScene).isEqualTo(CommunalScenes.Blank)
+ underTest.snapToScene(CommunalScenes.Communal)
+ assertThat(currentScene).isEqualTo(CommunalScenes.Communal)
underTest.setEditModeState(EditModeState.STARTING)
- underTest.snapToSceneForActivityStart(CommunalScenes.Communal)
- assertThat(currentScene).isEqualTo(CommunalScenes.Blank)
+
+ underTest.changeSceneForActivityStartOnDismissKeyguard()
+ assertThat(currentScene).isEqualTo(CommunalScenes.Communal)
}
@Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceconfig/data/repository/DeviceConfigRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceconfig/data/repository/DeviceConfigRepositoryTest.kt
new file mode 100644
index 0000000..79115ae
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceconfig/data/repository/DeviceConfigRepositoryTest.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
+package com.android.systemui.deviceconfig.data.repository
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.concurrency.fakeExecutor
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.testKosmos
+import com.android.systemui.util.fakeDeviceConfigProxy
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class DeviceConfigRepositoryTest : SysuiTestCase() {
+
+ private val kosmos = testKosmos()
+ private val testScope = kosmos.testScope
+ private val dataSource = kosmos.fakeDeviceConfigProxy
+
+ private val underTest = kosmos.deviceConfigRepository
+
+ @Test
+ fun booleanProperty() =
+ testScope.runTest {
+ val property by collectLastValue(underTest.property("namespace", "name", false))
+ assertThat(property).isFalse()
+
+ dataSource.setProperty("namespace", "name", "true", /* makeDefault= */ false)
+ kosmos.fakeExecutor.runAllReady()
+ assertThat(property).isTrue()
+
+ dataSource.setProperty("namespace", "name", "false", /* makeDefault= */ false)
+ kosmos.fakeExecutor.runAllReady()
+ assertThat(property).isFalse()
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceconfig/domain/interactor/DeviceConfigInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceconfig/domain/interactor/DeviceConfigInteractorTest.kt
new file mode 100644
index 0000000..6ec4cea
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceconfig/domain/interactor/DeviceConfigInteractorTest.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.deviceconfig.domain.interactor
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.concurrency.fakeExecutor
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.testKosmos
+import com.android.systemui.util.fakeDeviceConfigProxy
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class DeviceConfigInteractorTest : SysuiTestCase() {
+
+ private val kosmos = testKosmos()
+ private val testScope = kosmos.testScope
+ private val dataSource = kosmos.fakeDeviceConfigProxy
+
+ private val underTest = kosmos.deviceConfigInteractor
+
+ @Test
+ fun booleanProperty() =
+ testScope.runTest {
+ val property by collectLastValue(underTest.property("namespace", "name", false))
+ assertThat(property).isFalse()
+
+ dataSource.setProperty("namespace", "name", "true", /* makeDefault= */ false)
+ kosmos.fakeExecutor.runAllReady()
+ assertThat(property).isTrue()
+
+ dataSource.setProperty("namespace", "name", "false", /* makeDefault= */ false)
+ kosmos.fakeExecutor.runAllReady()
+ assertThat(property).isFalse()
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt
index ee8a22c..5a39de8 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt
@@ -778,6 +778,7 @@
DREAM_COMPONENT,
false /*shouldShowComplication*/
)
+ testScope.runCurrent()
mMainExecutor.runAllReady()
assertThat(lifecycleRegistry.currentState).isEqualTo(Lifecycle.State.STARTED)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/qs/QSLongPressEffectTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/qs/QSLongPressEffectTest.kt
index 3d3c778..74eee9b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/qs/QSLongPressEffectTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/qs/QSLongPressEffectTest.kt
@@ -144,7 +144,7 @@
longPressEffect.handleActionUp()
// THEN the effect reverses
- assertEffectReverses()
+ assertEffectReverses(QSLongPressEffect.State.RUNNING_BACKWARDS_FROM_UP)
}
@Test
@@ -171,18 +171,17 @@
longPressEffect.handleActionCancel()
// THEN the effect gets reversed
- assertEffectReverses()
+ assertEffectReverses(QSLongPressEffect.State.RUNNING_BACKWARDS_FROM_CANCEL)
}
@Test
- fun onAnimationComplete_keyguardDismissible_effectEndsWithPrepare() =
+ fun onAnimationComplete_keyguardDismissible_effectCompletes() =
testWhileInState(QSLongPressEffect.State.RUNNING_FORWARD) {
// GIVEN that the animation completes
longPressEffect.handleAnimationComplete()
- // THEN the long-press effect completes and the view is called to prepare
+ // THEN the long-press effect completes
assertEffectCompleted()
- verify(callback, times(1)).onPrepareForLaunch()
}
@Test
@@ -200,6 +199,26 @@
}
@Test
+ fun onAnimationComplete_whenRunningBackwardsFromUp_endsWithFinishedReversing() =
+ testWhileInState(QSLongPressEffect.State.RUNNING_BACKWARDS_FROM_UP) {
+ // GIVEN that the animation completes
+ longPressEffect.handleAnimationComplete()
+
+ // THEN the callback for finished reversing is used.
+ verify(callback, times(1)).onEffectFinishedReversing()
+ }
+
+ @Test
+ fun onAnimationComplete_whenRunningBackwardsFromCancel_endsInIdle() =
+ testWhileInState(QSLongPressEffect.State.RUNNING_BACKWARDS_FROM_CANCEL) {
+ // GIVEN that the animation completes
+ longPressEffect.handleAnimationComplete()
+
+ // THEN the effect ends in the idle state.
+ assertThat(longPressEffect.state).isEqualTo(QSLongPressEffect.State.IDLE)
+ }
+
+ @Test
fun onActionDown_whileRunningBackwards_cancels() =
testWhileInState(QSLongPressEffect.State.RUNNING_FORWARD) {
// GIVEN an action cancel occurs and the effect gets reversed
@@ -223,11 +242,8 @@
}
@Test
- fun onAnimationComplete_whileRunningBackwards_goesToIdle() =
- testWhileInState(QSLongPressEffect.State.RUNNING_BACKWARDS) {
- // GIVEN an action cancel occurs and the effect gets reversed
- longPressEffect.handleActionCancel()
-
+ fun onAnimationComplete_whileRunningBackwardsFromCancel_goesToIdle() =
+ testWhileInState(QSLongPressEffect.State.RUNNING_BACKWARDS_FROM_CANCEL) {
// GIVEN that the animation completes
longPressEffect.handleAnimationComplete()
@@ -307,12 +323,16 @@
/**
* Asserts that the effect did not start by checking that:
* 1. No haptics are played
- * 2. The internal state is not [QSLongPressEffect.State.RUNNING_BACKWARDS] or
- * [QSLongPressEffect.State.RUNNING_FORWARD]
+ * 2. The internal state is not [QSLongPressEffect.State.RUNNING_BACKWARDS_FROM_UP] or
+ * [QSLongPressEffect.State.RUNNING_FORWARD] or
+ * [QSLongPressEffect.State.RUNNING_BACKWARDS_FROM_CANCEL]
*/
private fun assertEffectDidNotStart() {
assertThat(longPressEffect.state).isNotEqualTo(QSLongPressEffect.State.RUNNING_FORWARD)
- assertThat(longPressEffect.state).isNotEqualTo(QSLongPressEffect.State.RUNNING_BACKWARDS)
+ assertThat(longPressEffect.state)
+ .isNotEqualTo(QSLongPressEffect.State.RUNNING_BACKWARDS_FROM_UP)
+ assertThat(longPressEffect.state)
+ .isNotEqualTo(QSLongPressEffect.State.RUNNING_BACKWARDS_FROM_CANCEL)
assertThat(vibratorHelper.totalVibrations).isEqualTo(0)
}
@@ -330,12 +350,14 @@
}
/**
- * Assert that the effect gets reverted by checking that:
- * 1. The internal state is [QSLongPressEffect.State.RUNNING_BACKWARDS]
- * 2. An action to reverse the animator is emitted
+ * Assert that the effect gets reverted by checking that the callback to reverse the animator is
+ * used, and that the state is given reversing state.
+ *
+ * @param[reversingState] Either [QSLongPressEffect.State.RUNNING_BACKWARDS_FROM_CANCEL] or
+ * [QSLongPressEffect.State.RUNNING_BACKWARDS_FROM_UP]
*/
- private fun assertEffectReverses() {
- assertThat(longPressEffect.state).isEqualTo(QSLongPressEffect.State.RUNNING_BACKWARDS)
+ private fun assertEffectReverses(reversingState: QSLongPressEffect.State) {
+ assertThat(longPressEffect.state).isEqualTo(reversingState)
verify(callback, times(1)).onReverseAnimator()
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
index 5dac37a..48caf3e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
@@ -140,6 +140,27 @@
}
@Test
+ fun panelAlpha() =
+ testScope.runTest {
+ assertThat(underTest.panelAlpha.value).isEqualTo(1f)
+
+ underTest.setPanelAlpha(0.1f)
+ assertThat(underTest.panelAlpha.value).isEqualTo(0.1f)
+
+ underTest.setPanelAlpha(0.2f)
+ assertThat(underTest.panelAlpha.value).isEqualTo(0.2f)
+
+ underTest.setPanelAlpha(0.3f)
+ assertThat(underTest.panelAlpha.value).isEqualTo(0.3f)
+
+ underTest.setPanelAlpha(0.5f)
+ assertThat(underTest.panelAlpha.value).isEqualTo(0.5f)
+
+ underTest.setPanelAlpha(1.0f)
+ assertThat(underTest.panelAlpha.value).isEqualTo(1f)
+ }
+
+ @Test
fun topClippingBounds() =
testScope.runTest {
assertThat(underTest.topClippingBounds.value).isNull()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelTest.kt
index 519bb6e..63d06a4 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelTest.kt
@@ -55,6 +55,8 @@
@Mock private lateinit var burnInInteractor: BurnInInteractor
@Mock private lateinit var goneToAodTransitionViewModel: GoneToAodTransitionViewModel
+ @Mock
+ private lateinit var lockscreenToAodTransitionViewModel: LockscreenToAodTransitionViewModel
@Mock(answer = Answers.RETURNS_DEEP_STUBS) private lateinit var clockController: ClockController
private val kosmos = testKosmos()
@@ -76,7 +78,12 @@
kosmos.burnInInteractor = burnInInteractor
whenever(goneToAodTransitionViewModel.enterFromTopTranslationY(anyInt()))
.thenReturn(emptyFlow())
+ whenever(goneToAodTransitionViewModel.enterFromSideTranslationX(anyInt()))
+ .thenReturn(emptyFlow())
+ whenever(lockscreenToAodTransitionViewModel.enterFromSideTranslationX(anyInt()))
+ .thenReturn(emptyFlow())
kosmos.goneToAodTransitionViewModel = goneToAodTransitionViewModel
+ kosmos.lockscreenToAodTransitionViewModel = lockscreenToAodTransitionViewModel
kosmos.fakeKeyguardClockRepository.setCurrentClock(clockController)
underTest = kosmos.aodBurnInViewModel
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModelTest.kt
similarity index 71%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModelTest.kt
index 716c40d..bab466a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModelTest.kt
@@ -28,6 +28,9 @@
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.keyguard.ui.StateToValue
import com.android.systemui.kosmos.testScope
+import com.android.systemui.power.data.repository.powerRepository
+import com.android.systemui.power.shared.model.WakeSleepReason
+import com.android.systemui.power.shared.model.WakefulnessState
import com.android.systemui.testKosmos
import com.google.common.collect.Range
import com.google.common.truth.Truth.assertThat
@@ -47,10 +50,18 @@
private val underTest = kosmos.goneToAodTransitionViewModel
private val fingerprintPropertyRepository = kosmos.fingerprintPropertyRepository
private val biometricSettingsRepository = kosmos.biometricSettingsRepository
+ private val powerRepository = kosmos.powerRepository
@Test
- fun enterFromTopTranslationY() =
+ fun enterFromTopTranslationY_whenNotOnFold() =
testScope.runTest {
+ powerRepository.updateWakefulness(
+ rawState = WakefulnessState.STARTING_TO_SLEEP,
+ lastWakeReason = WakeSleepReason.POWER_BUTTON,
+ lastSleepReason = WakeSleepReason.POWER_BUTTON,
+ powerButtonLaunchGestureTriggered = false
+ )
+
val pixels = -100f
val enterFromTopTranslationY by
collectLastValue(underTest.enterFromTopTranslationY(pixels.toInt()))
@@ -88,6 +99,80 @@
}
@Test
+ fun enterFromTopTranslationY_whenOnFold_emitsNothing() =
+ testScope.runTest {
+ powerRepository.updateWakefulness(
+ rawState = WakefulnessState.STARTING_TO_SLEEP,
+ lastWakeReason = WakeSleepReason.POWER_BUTTON,
+ lastSleepReason = WakeSleepReason.FOLD,
+ powerButtonLaunchGestureTriggered = false
+ )
+
+ val pixels = -100f
+ val enterFromTopTranslationY by
+ collectLastValue(underTest.enterFromTopTranslationY(pixels.toInt()))
+ runCurrent()
+
+ repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+ assertThat(enterFromTopTranslationY).isNull()
+
+ repository.sendTransitionStep(step(.55f))
+ assertThat(enterFromTopTranslationY).isNull()
+
+ repository.sendTransitionStep(step(.85f))
+ assertThat(enterFromTopTranslationY).isNull()
+
+ repository.sendTransitionStep(step(1f))
+ assertThat(enterFromTopTranslationY).isNull()
+ }
+
+ @Test
+ fun enterFromSideTranslationX_onFold() =
+ testScope.runTest {
+ powerRepository.updateWakefulness(
+ rawState = WakefulnessState.STARTING_TO_SLEEP,
+ lastWakeReason = WakeSleepReason.POWER_BUTTON,
+ lastSleepReason = WakeSleepReason.FOLD,
+ powerButtonLaunchGestureTriggered = false
+ )
+
+ val pixels = -100f
+ val enterFromSideTranslationX by
+ collectLastValue(underTest.enterFromSideTranslationX(pixels.toInt()))
+ runCurrent()
+
+ // The animation should only start > .4f way through
+ repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+ assertThat(enterFromSideTranslationX)
+ .isEqualTo(
+ StateToValue(
+ from = KeyguardState.GONE,
+ to = KeyguardState.AOD,
+ transitionState = TransitionState.STARTED,
+ value = pixels
+ )
+ )
+
+ repository.sendTransitionStep(step(.55f))
+ assertThat(enterFromSideTranslationX!!.value ?: -1f).isIn(Range.closed(pixels, 0f))
+
+ repository.sendTransitionStep(step(.85f))
+ assertThat(enterFromSideTranslationX!!.value ?: -1f).isIn(Range.closed(pixels, 0f))
+
+ // At the end, the translation should be complete and set to zero
+ repository.sendTransitionStep(step(1f))
+ assertThat(enterFromSideTranslationX)
+ .isEqualTo(
+ StateToValue(
+ from = KeyguardState.GONE,
+ to = KeyguardState.AOD,
+ transitionState = TransitionState.RUNNING,
+ value = 0f
+ )
+ )
+ }
+
+ @Test
fun enterFromTopAnimationAlpha() =
testScope.runTest {
val enterFromTopAnimationAlpha by collectLastValue(underTest.enterFromTopAnimationAlpha)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/navigation/data/repository/NavigationRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/navigation/data/repository/NavigationRepositoryTest.kt
new file mode 100644
index 0000000..e45aa05
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/navigation/data/repository/NavigationRepositoryTest.kt
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.navigation.data.repository
+
+import android.view.WindowManagerPolicyConstants
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.navigationbar.NavigationModeController.ModeChangedListener
+import com.android.systemui.navigationbar.navigationModeController
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.any
+import org.mockito.kotlin.whenever
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class NavigationRepositoryTest : SysuiTestCase() {
+
+ private val kosmos = testKosmos()
+ private val testScope = kosmos.testScope
+ private val navigationModeControllerMock = kosmos.navigationModeController
+
+ private val underTest = kosmos.navigationRepository
+
+ private var currentMode = WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON
+ private val modeChangedListeners = mutableListOf<ModeChangedListener>()
+
+ @Before
+ fun setUp() {
+ whenever(navigationModeControllerMock.addListener(any())).thenAnswer { invocation ->
+ val listener = invocation.arguments[0] as ModeChangedListener
+ modeChangedListeners.add(listener)
+ currentMode
+ }
+ }
+
+ @Test
+ fun isGesturalMode() =
+ testScope.runTest {
+ val isGesturalMode by collectLastValue(underTest.isGesturalMode)
+ assertThat(isGesturalMode).isFalse()
+
+ currentMode = WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL
+ notifyModeChangedListeners()
+ assertThat(isGesturalMode).isTrue()
+
+ currentMode = WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON
+ notifyModeChangedListeners()
+ assertThat(isGesturalMode).isFalse()
+ }
+
+ private fun notifyModeChangedListeners() {
+ modeChangedListeners.forEach { listener -> listener.onNavigationModeChanged(currentMode) }
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/navigation/domain/interactor/NavigationInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/navigation/domain/interactor/NavigationInteractorTest.kt
new file mode 100644
index 0000000..88beeb2
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/navigation/domain/interactor/NavigationInteractorTest.kt
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.navigation.domain.interactor
+
+import android.view.WindowManagerPolicyConstants
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.navigationbar.NavigationModeController.ModeChangedListener
+import com.android.systemui.navigationbar.navigationModeController
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.any
+import org.mockito.kotlin.whenever
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class NavigationInteractorTest : SysuiTestCase() {
+
+ private val kosmos = testKosmos()
+ private val testScope = kosmos.testScope
+ private val navigationModeControllerMock = kosmos.navigationModeController
+
+ private val underTest = kosmos.navigationInteractor
+
+ private var currentMode = WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON
+ private val modeChangedListeners = mutableListOf<ModeChangedListener>()
+
+ @Before
+ fun setUp() {
+ whenever(navigationModeControllerMock.addListener(any())).thenAnswer { invocation ->
+ val listener = invocation.arguments[0] as ModeChangedListener
+ modeChangedListeners.add(listener)
+ currentMode
+ }
+ }
+
+ @Test
+ fun isGesturalMode() =
+ testScope.runTest {
+ val isGesturalMode by collectLastValue(underTest.isGesturalMode)
+ assertThat(isGesturalMode).isFalse()
+
+ currentMode = WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL
+ notifyModeChangedListeners()
+ assertThat(isGesturalMode).isTrue()
+
+ currentMode = WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON
+ notifyModeChangedListeners()
+ assertThat(isGesturalMode).isFalse()
+ }
+
+ private fun notifyModeChangedListeners() {
+ modeChangedListeners.forEach { listener -> listener.onNavigationModeChanged(currentMode) }
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/CastAutoAddableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/CastAutoAddableTest.kt
index 9bb591e..8ad647d 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/CastAutoAddableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/CastAutoAddableTest.kt
@@ -25,6 +25,7 @@
import com.android.systemui.qs.pipeline.shared.TileSpec
import com.android.systemui.qs.tiles.CastTile
import com.android.systemui.statusbar.policy.CastController
+import com.android.systemui.statusbar.policy.CastDevice
import com.android.systemui.util.mockito.capture
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
@@ -73,9 +74,12 @@
@Test
fun onCastDevicesChanged_deviceNotConnectedOrConnecting_noSignal() = runTest {
val device =
- CastController.CastDevice().apply {
- state = CastController.CastDevice.STATE_DISCONNECTED
- }
+ CastDevice(
+ id = "id",
+ name = null,
+ state = CastDevice.CastState.Disconnected,
+ origin = CastDevice.CastOrigin.MediaProjection,
+ )
whenever(castController.castDevices).thenReturn(listOf(device))
val signal by collectLastValue(underTest.autoAddSignal(0))
@@ -91,11 +95,19 @@
@Test
fun onCastDevicesChanged_someDeviceConnecting_addSignal() = runTest {
val disconnectedDevice =
- CastController.CastDevice().apply {
- state = CastController.CastDevice.STATE_DISCONNECTED
- }
+ CastDevice(
+ id = "id",
+ name = null,
+ state = CastDevice.CastState.Disconnected,
+ origin = CastDevice.CastOrigin.MediaProjection,
+ )
val connectingDevice =
- CastController.CastDevice().apply { state = CastController.CastDevice.STATE_CONNECTING }
+ CastDevice(
+ id = "id",
+ name = null,
+ state = CastDevice.CastState.Connecting,
+ origin = CastDevice.CastOrigin.MediaProjection,
+ )
whenever(castController.castDevices)
.thenReturn(listOf(disconnectedDevice, connectingDevice))
@@ -112,11 +124,19 @@
@Test
fun onCastDevicesChanged_someDeviceConnected_addSignal() = runTest {
val disconnectedDevice =
- CastController.CastDevice().apply {
- state = CastController.CastDevice.STATE_DISCONNECTED
- }
+ CastDevice(
+ id = "id",
+ name = null,
+ state = CastDevice.CastState.Disconnected,
+ origin = CastDevice.CastOrigin.MediaProjection,
+ )
val connectedDevice =
- CastController.CastDevice().apply { state = CastController.CastDevice.STATE_CONNECTED }
+ CastDevice(
+ id = "id",
+ name = null,
+ state = CastDevice.CastState.Connected,
+ origin = CastDevice.CastOrigin.MediaProjection,
+ )
whenever(castController.castDevices).thenReturn(listOf(disconnectedDevice, connectedDevice))
val signal by collectLastValue(underTest.autoAddSignal(0))
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/base/logging/QSTileLoggerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/base/logging/QSTileLoggerTest.kt
index b7e08da..ff40e43 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/base/logging/QSTileLoggerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/base/logging/QSTileLoggerTest.kt
@@ -54,7 +54,7 @@
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
- whenever(logBufferFactory.create(any(), any(), any())).thenReturn(logBuffer)
+ whenever(logBufferFactory.create(any(), any(), any(), any())).thenReturn(logBuffer)
val tileSpec: TileSpec = TileSpec.create("chatty_tile")
underTest =
QSTileLogger(mapOf(tileSpec to chattyLogBuffer), logBufferFactory, statusBarController)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/smartspace/CommunalSmartspaceControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/smartspace/CommunalSmartspaceControllerTest.kt
index ad4b98b..eac86e5 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/smartspace/CommunalSmartspaceControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/smartspace/CommunalSmartspaceControllerTest.kt
@@ -20,6 +20,7 @@
import android.app.smartspace.SmartspaceTarget
import android.content.Context
import android.graphics.drawable.Drawable
+import android.os.Handler
import android.testing.TestableLooper
import android.view.View
import android.widget.FrameLayout
@@ -86,6 +87,8 @@
override fun setUiSurface(uiSurface: String) {}
+ override fun setBgHandler(bgHandler: Handler?) {}
+
override fun setDozeAmount(amount: Float) {}
override fun setIntentStarter(intentStarter: BcSmartspaceDataPlugin.IntentStarter?) {}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/smartspace/DreamSmartspaceControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/smartspace/DreamSmartspaceControllerTest.kt
index 3a38631..e774aed 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/smartspace/DreamSmartspaceControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/smartspace/DreamSmartspaceControllerTest.kt
@@ -20,6 +20,7 @@
import android.app.smartspace.SmartspaceTarget
import android.content.Context
import android.graphics.drawable.Drawable
+import android.os.Handler
import android.testing.TestableLooper
import android.view.View
import android.view.ViewGroup
@@ -119,6 +120,8 @@
override fun setUiSurface(uiSurface: String) {}
+ override fun setBgHandler(bgHandler: Handler?) {}
+
override fun setDozeAmount(amount: Float) {}
override fun setIntentStarter(intentStarter: BcSmartspaceDataPlugin.IntentStarter?) {}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationStackAppearanceIntegrationTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationStackAppearanceIntegrationTest.kt
index ca4434d2..cc3fdc5 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationStackAppearanceIntegrationTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationStackAppearanceIntegrationTest.kt
@@ -32,6 +32,8 @@
import com.android.systemui.scene.shared.model.fakeSceneDataSource
import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrimBounds
import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrimShape
+import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationTransitionThresholds.EXPANSION_FOR_DELAYED_STACK_FADE_IN
+import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationTransitionThresholds.EXPANSION_FOR_MAX_SCRIM_ALPHA
import com.android.systemui.statusbar.notification.stack.ui.viewmodel.notificationScrollViewModel
import com.android.systemui.statusbar.notification.stack.ui.viewmodel.notificationsPlaceholderViewModel
import com.android.systemui.testKosmos
@@ -208,4 +210,50 @@
assertThat(expandFraction).isEqualTo(1f)
assertThat(isScrollable).isFalse()
}
+
+ @Test
+ fun shadeExpansion_goneToQs() =
+ testScope.runTest {
+ val transitionState =
+ MutableStateFlow<ObservableTransitionState>(
+ ObservableTransitionState.Idle(currentScene = Scenes.Gone)
+ )
+ sceneInteractor.setTransitionState(transitionState)
+ val expandFraction by collectLastValue(scrollViewModel.expandFraction)
+ assertThat(expandFraction).isEqualTo(0f)
+
+ fakeSceneDataSource.changeScene(toScene = Scenes.Gone)
+ val isScrollable by collectLastValue(scrollViewModel.isScrollable)
+ assertThat(isScrollable).isFalse()
+
+ fakeSceneDataSource.pause()
+
+ sceneInteractor.changeScene(Scenes.QuickSettings, "reason")
+ val transitionProgress = MutableStateFlow(0f)
+ transitionState.value =
+ ObservableTransitionState.Transition(
+ fromScene = Scenes.Gone,
+ toScene = Scenes.QuickSettings,
+ currentScene = flowOf(Scenes.QuickSettings),
+ progress = transitionProgress,
+ isInitiatedByUserInput = false,
+ isUserInputOngoing = flowOf(false),
+ )
+ val steps = 10
+ repeat(steps) { repetition ->
+ val progress = (1f / steps) * (repetition + 1)
+ transitionProgress.value = progress
+ runCurrent()
+ assertThat(expandFraction)
+ .isEqualTo(
+ (progress / EXPANSION_FOR_MAX_SCRIM_ALPHA -
+ EXPANSION_FOR_DELAYED_STACK_FADE_IN)
+ .coerceIn(0f, 1f)
+ )
+ }
+
+ fakeSceneDataSource.unpause(expectedScene = Scenes.QuickSettings)
+ assertThat(expandFraction).isEqualTo(1f)
+ assertThat(isScrollable).isFalse()
+ }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
index 497484f90..f14c96ded 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
@@ -23,11 +23,15 @@
import android.platform.test.annotations.EnableFlags
import android.platform.test.flag.junit.FlagsParameterization
import androidx.test.filters.SmallTest
+import com.android.compose.animation.scene.ObservableTransitionState
import com.android.systemui.Flags.FLAG_CENTRALIZED_STATUS_BAR_HEIGHT_FIX
import com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT
import com.android.systemui.SysuiTestCase
+import com.android.systemui.bouncer.data.repository.keyguardBouncerRepository
import com.android.systemui.common.shared.model.NotificationContainerBounds
import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
+import com.android.systemui.communal.data.repository.communalSceneRepository
+import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.coroutines.collectValues
import com.android.systemui.flags.BrokenWithSceneContainer
@@ -134,6 +138,9 @@
val largeScreenHeaderHelper
get() = kosmos.mockLargeScreenHeaderHelper
+ val communalSceneRepository
+ get() = kosmos.communalSceneRepository
+
lateinit var underTest: SharedNotificationContainerViewModel
@Before
@@ -845,26 +852,24 @@
@Test
@DisableSceneContainer
fun updateBounds_fromGone_withoutTransitions() =
- testScope.runTest {
- // Start step is already at 1.0
- val runningStep = TransitionStep(GONE, AOD, 1.0f, TransitionState.RUNNING)
- val finishStep = TransitionStep(GONE, AOD, 1.0f, TransitionState.FINISHED)
+ testScope.runTest {
+ // Start step is already at 1.0
+ val runningStep = TransitionStep(GONE, AOD, 1.0f, TransitionState.RUNNING)
+ val finishStep = TransitionStep(GONE, AOD, 1.0f, TransitionState.FINISHED)
- val bounds by collectLastValue(underTest.bounds)
- val top = 123f
- val bottom = 456f
+ val bounds by collectLastValue(underTest.bounds)
+ val top = 123f
+ val bottom = 456f
- kosmos.fakeKeyguardTransitionRepository.sendTransitionStep(runningStep)
- runCurrent()
- kosmos.fakeKeyguardTransitionRepository.sendTransitionStep(finishStep)
- runCurrent()
- keyguardRootViewModel.onNotificationContainerBoundsChanged(top, bottom)
- runCurrent()
+ kosmos.fakeKeyguardTransitionRepository.sendTransitionStep(runningStep)
+ runCurrent()
+ kosmos.fakeKeyguardTransitionRepository.sendTransitionStep(finishStep)
+ runCurrent()
+ keyguardRootViewModel.onNotificationContainerBoundsChanged(top, bottom)
+ runCurrent()
- assertThat(bounds).isEqualTo(
- NotificationContainerBounds(top = top, bottom = bottom)
- )
- }
+ assertThat(bounds).isEqualTo(NotificationContainerBounds(top = top, bottom = bottom))
+ }
@Test
fun alphaOnFullQsExpansion() =
@@ -1020,6 +1025,230 @@
assertThat(fadeIn[0]).isEqualTo(false)
}
+ @Test
+ @BrokenWithSceneContainer(330311871)
+ fun alpha_isZero_fromPrimaryBouncerToGoneWhileCommunalSceneVisible() =
+ testScope.runTest {
+ val viewState = ViewStateAccessor()
+ val alpha by collectLastValue(underTest.keyguardAlpha(viewState))
+
+ showPrimaryBouncer()
+ showCommunalScene()
+
+ // PRIMARY_BOUNCER->GONE transition is started
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ from = KeyguardState.PRIMARY_BOUNCER,
+ to = GONE,
+ transitionState = TransitionState.STARTED,
+ value = 0f,
+ )
+ )
+ runCurrent()
+
+ // PRIMARY_BOUNCER->GONE transition running
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ from = KeyguardState.PRIMARY_BOUNCER,
+ to = GONE,
+ transitionState = TransitionState.RUNNING,
+ value = 0.1f,
+ )
+ )
+ runCurrent()
+ assertThat(alpha).isEqualTo(0f)
+
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ from = KeyguardState.PRIMARY_BOUNCER,
+ to = GONE,
+ transitionState = TransitionState.RUNNING,
+ value = 0.9f,
+ )
+ )
+ runCurrent()
+ assertThat(alpha).isEqualTo(0f)
+
+ hideCommunalScene()
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ from = KeyguardState.PRIMARY_BOUNCER,
+ to = GONE,
+ transitionState = TransitionState.FINISHED,
+ value = 1f
+ )
+ )
+ runCurrent()
+ assertThat(alpha).isEqualTo(0f)
+ }
+
+ @Test
+ @BrokenWithSceneContainer(330311871)
+ fun alpha_fromPrimaryBouncerToGoneWhenCommunalSceneNotVisible() =
+ testScope.runTest {
+ val viewState = ViewStateAccessor()
+ val alpha by collectLastValue(underTest.keyguardAlpha(viewState))
+
+ showPrimaryBouncer()
+ hideCommunalScene()
+
+ // PRIMARY_BOUNCER->GONE transition is started
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ from = KeyguardState.PRIMARY_BOUNCER,
+ to = GONE,
+ transitionState = TransitionState.STARTED,
+ )
+ )
+ runCurrent()
+
+ // PRIMARY_BOUNCER->GONE transition running
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ from = KeyguardState.PRIMARY_BOUNCER,
+ to = GONE,
+ transitionState = TransitionState.RUNNING,
+ value = 0.1f,
+ )
+ )
+ runCurrent()
+ assertThat(alpha).isIn(Range.closedOpen(0f, 1f))
+
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ from = KeyguardState.PRIMARY_BOUNCER,
+ to = GONE,
+ transitionState = TransitionState.RUNNING,
+ value = 0.9f,
+ )
+ )
+ runCurrent()
+ assertThat(alpha).isIn(Range.closedOpen(0f, 1f))
+
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ from = KeyguardState.PRIMARY_BOUNCER,
+ to = GONE,
+ transitionState = TransitionState.FINISHED,
+ value = 1f
+ )
+ )
+ runCurrent()
+ assertThat(alpha).isEqualTo(0f)
+ }
+
+ @Test
+ @BrokenWithSceneContainer(330311871)
+ fun alpha_isZero_fromAlternateBouncerToGoneWhileCommunalSceneVisible() =
+ testScope.runTest {
+ val viewState = ViewStateAccessor()
+ val alpha by collectLastValue(underTest.keyguardAlpha(viewState))
+
+ showAlternateBouncer()
+ showCommunalScene()
+
+ // ALTERNATE_BOUNCER->GONE transition is started
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ from = KeyguardState.ALTERNATE_BOUNCER,
+ to = GONE,
+ transitionState = TransitionState.STARTED,
+ value = 0f,
+ )
+ )
+ runCurrent()
+
+ // ALTERNATE_BOUNCER->GONE transition running
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ from = KeyguardState.ALTERNATE_BOUNCER,
+ to = GONE,
+ transitionState = TransitionState.RUNNING,
+ value = 0.1f,
+ )
+ )
+ runCurrent()
+ assertThat(alpha).isEqualTo(0f)
+
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ from = KeyguardState.ALTERNATE_BOUNCER,
+ to = GONE,
+ transitionState = TransitionState.RUNNING,
+ value = 0.9f,
+ )
+ )
+ runCurrent()
+ assertThat(alpha).isEqualTo(0f)
+
+ hideCommunalScene()
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ from = KeyguardState.ALTERNATE_BOUNCER,
+ to = GONE,
+ transitionState = TransitionState.FINISHED,
+ value = 1f
+ )
+ )
+ runCurrent()
+ assertThat(alpha).isEqualTo(0f)
+ }
+
+ @Test
+ @BrokenWithSceneContainer(330311871)
+ fun alpha_fromAlternateBouncerToGoneWhenCommunalSceneNotVisible() =
+ testScope.runTest {
+ val viewState = ViewStateAccessor()
+ val alpha by collectLastValue(underTest.keyguardAlpha(viewState))
+
+ showAlternateBouncer()
+ hideCommunalScene()
+
+ // ALTERNATE_BOUNCER->GONE transition is started
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ from = KeyguardState.ALTERNATE_BOUNCER,
+ to = GONE,
+ transitionState = TransitionState.STARTED,
+ )
+ )
+ runCurrent()
+
+ // ALTERNATE_BOUNCER->GONE transition running
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ from = KeyguardState.ALTERNATE_BOUNCER,
+ to = GONE,
+ transitionState = TransitionState.RUNNING,
+ value = 0.1f,
+ )
+ )
+ runCurrent()
+ assertThat(alpha).isIn(Range.closedOpen(0f, 1f))
+
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ from = KeyguardState.ALTERNATE_BOUNCER,
+ to = GONE,
+ transitionState = TransitionState.RUNNING,
+ value = 0.9f,
+ )
+ )
+ runCurrent()
+ assertThat(alpha).isIn(Range.closedOpen(0f, 1f))
+
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ from = KeyguardState.ALTERNATE_BOUNCER,
+ to = GONE,
+ transitionState = TransitionState.FINISHED,
+ value = 1f
+ )
+ )
+ runCurrent()
+ assertThat(alpha).isEqualTo(0f)
+ }
+
private suspend fun TestScope.showLockscreen() {
shadeTestUtil.setQsExpansion(0f)
shadeTestUtil.setLockscreenShadeExpansion(0f)
@@ -1071,4 +1300,52 @@
testScope,
)
}
+
+ private suspend fun TestScope.showPrimaryBouncer() {
+ shadeTestUtil.setQsExpansion(0f)
+ shadeTestUtil.setLockscreenShadeExpansion(0f)
+ runCurrent()
+ keyguardRepository.setStatusBarState(StatusBarState.KEYGUARD)
+ runCurrent()
+ kosmos.keyguardBouncerRepository.setPrimaryShow(true)
+ runCurrent()
+ keyguardTransitionRepository.sendTransitionSteps(
+ from = KeyguardState.GLANCEABLE_HUB,
+ to = KeyguardState.PRIMARY_BOUNCER,
+ testScope,
+ )
+ }
+
+ private suspend fun TestScope.showAlternateBouncer() {
+ shadeTestUtil.setQsExpansion(0f)
+ shadeTestUtil.setLockscreenShadeExpansion(0f)
+ runCurrent()
+ keyguardRepository.setStatusBarState(StatusBarState.KEYGUARD)
+ runCurrent()
+ kosmos.keyguardBouncerRepository.setPrimaryShow(false)
+ runCurrent()
+ keyguardTransitionRepository.sendTransitionSteps(
+ from = KeyguardState.GLANCEABLE_HUB,
+ to = KeyguardState.ALTERNATE_BOUNCER,
+ testScope,
+ )
+ }
+
+ private fun TestScope.showCommunalScene() {
+ val transitionState =
+ MutableStateFlow<ObservableTransitionState>(
+ ObservableTransitionState.Idle(CommunalScenes.Communal)
+ )
+ communalSceneRepository.setTransitionState(transitionState)
+ runCurrent()
+ }
+
+ private fun TestScope.hideCommunalScene() {
+ val transitionState =
+ MutableStateFlow<ObservableTransitionState>(
+ ObservableTransitionState.Idle(CommunalScenes.Blank)
+ )
+ communalSceneRepository.setTransitionState(transitionState)
+ runCurrent()
+ }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/LegacyActivityStarterInternalImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/LegacyActivityStarterInternalImplTest.kt
index 57d3251..1656a2e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/LegacyActivityStarterInternalImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/LegacyActivityStarterInternalImplTest.kt
@@ -60,6 +60,7 @@
import com.google.common.truth.Truth.assertThat
import java.util.Optional
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.MutableStateFlow
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -132,6 +133,7 @@
communalSceneInteractor = communalSceneInteractor,
)
whenever(userTracker.userHandle).thenReturn(UserHandle.OWNER)
+ whenever(communalSceneInteractor.isIdleOnCommunal).thenReturn(MutableStateFlow(false))
}
@Test
diff --git a/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java b/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java
index 9ad4012..074277c 100644
--- a/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java
+++ b/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java
@@ -24,6 +24,7 @@
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.graphics.drawable.Drawable;
+import android.os.Handler;
import android.os.Parcelable;
import android.util.Log;
import android.view.View;
@@ -123,6 +124,9 @@
*/
void setUiSurface(String uiSurface);
+ /** Set background handler to make binder calls. */
+ void setBgHandler(Handler bgHandler);
+
/**
* Range [0.0 - 1.0] when transitioning from Lockscreen to/from AOD
*/
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index c775336..fd768d8 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -1197,6 +1203,8 @@
<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>
<string name="accessibility_bouncer" msgid="5896923685673320070">"voer skermslot in"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Vingerafdruksensor"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"staaf"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"gaan by toestel in"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index de4138f..9c24d30 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -1195,6 +1201,8 @@
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"ለበለጠ መረጃ መታ ያድርጉ"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"ምንም ማንቂያ አልተቀናበረም"</string>
<string name="accessibility_bouncer" msgid="5896923685673320070">"ማያ ገጽ መቆለፊያ ያስገቡ"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"የጣት አሻራ ዳሳሽ"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"ያረጋግጡ"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"መሣሪያን ያስገቡ"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 8bd52d6..8711e78 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -1197,6 +1203,8 @@
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"انقر للحصول على مزيد من المعلومات."</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"لم يتم ضبط منبّه"</string>
<string name="accessibility_bouncer" msgid="5896923685673320070">"إدخال الرمز لفتح القفل"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"مستشعر بصمات الإصبع"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"المصادقة"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"الدخول إلى الجهاز"</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 77774cc..785f3f4 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -303,10 +309,8 @@
<skip />
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Quick Share আৰু Find My Deviceৰ দৰে সুবিধাসমূহে ব্লুটুথ ব্যৱহাৰ কৰে"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"কাইলৈ পুৱা ব্লুটুথ অন হ’ব"</string>
- <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
- <skip />
- <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
- <skip />
+ <string name="quick_settings_bluetooth_audio_sharing_button" msgid="7545274861795853838">"অডিঅ’ শ্বেয়াৰ কৰক"</string>
+ <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="3069309588231072128">"অডিঅ’ শ্বেয়াৰ কৰি থকা হৈছে"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"বেটাৰী <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"অডিঅ’"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"হেডছেট"</string>
@@ -1197,6 +1201,8 @@
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"অধিক তথ্যৰ বাবে টিপক"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"কোনো এলাৰ্ম ছেট কৰা হোৱা নাই"</string>
<string name="accessibility_bouncer" msgid="5896923685673320070">"স্ক্ৰীন লকটো দিয়ক"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"ফিংগাৰপ্ৰিণ্ট ছেন্সৰ"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"বিশ্বাসযোগ্যতা প্ৰমাণ কৰক"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"ডিভাইচ আনলক কৰক"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index bf24c07..1c75a9b3 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -1197,6 +1203,8 @@
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Ətraflı məlumat üçün toxunun"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Siqnal ayarlanmayıb"</string>
<string name="accessibility_bouncer" msgid="5896923685673320070">"ekran kilidi daxil edin"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Barmaq izi sensoru"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"doğrulayın"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"cihaz daxil edin"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 02271f0..6072605 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -303,10 +309,8 @@
<skip />
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Funkcije kao što su Quick Share i Pronađi moj uređaj koriste Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth će se uključiti sutra ujutru"</string>
- <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
- <skip />
- <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
- <skip />
+ <string name="quick_settings_bluetooth_audio_sharing_button" msgid="7545274861795853838">"Deli zvuk"</string>
+ <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="3069309588231072128">"Deli se zvuk"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Nivo baterije je <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Slušalice"</string>
@@ -1197,6 +1201,8 @@
<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 podešen"</string>
<string name="accessibility_bouncer" msgid="5896923685673320070">"unesite otključavanje ekrana"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Senzor za otisak prsta"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"potvrdite identitet"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"unesite uređaj"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index ed44819..df1227f 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -303,10 +309,8 @@
<skip />
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Bluetooth выкарыстоўваецца такімі функцыямі і сэрвісамі, як Хуткае абагульванне і Знайсці прыладу"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth уключыцца заўтра раніцай"</string>
- <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
- <skip />
- <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
- <skip />
+ <string name="quick_settings_bluetooth_audio_sharing_button" msgid="7545274861795853838">"Абагуліць аўдыя"</string>
+ <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="3069309588231072128">"Ідзе абагульванне аўдыя"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Узровень зараду: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Гук"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Гарнітура"</string>
@@ -379,7 +383,7 @@
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Пачаць"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Спыніць"</string>
<string name="qs_record_issue_label" msgid="8166290137285529059">"Запіс праблемы"</string>
- <string name="qs_record_issue_start" msgid="2979831312582567056">"Пачынайце"</string>
+ <string name="qs_record_issue_start" msgid="2979831312582567056">"Пачаць"</string>
<string name="qs_record_issue_stop" msgid="3531747965741982657">"Спыніцеся"</string>
<string name="qs_record_issue_bug_report" msgid="8229031766918650079">"Справаздача"</string>
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"З чым была звязана праблема, якая вам сустрэлася?"</string>
@@ -1197,6 +1201,8 @@
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Націсніце, каб убачыць больш"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Няма будзільнікаў"</string>
<string name="accessibility_bouncer" msgid="5896923685673320070">"прыступіць да разблакіроўкі экрана"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Сканер адбіткаў пальцаў"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"правесці аўтэнтыфікацыю"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"адкрыць галоўны экран прылады"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index b88e0e4..b7c8467 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -1197,6 +1203,8 @@
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Докоснете за още информация"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Няма зададен будилник"</string>
<string name="accessibility_bouncer" msgid="5896923685673320070">"въведете опция за заключване на екрана"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Сензор за отпечатъци"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"удостоверяване"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"вход в устройството"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 0e44b3c..9fa4c6e 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -1197,6 +1203,8 @@
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"আরও তথ্যের জন্য ট্যাপ করুন"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"কোনও অ্যালার্ম সেট করা নেই"</string>
<string name="accessibility_bouncer" msgid="5896923685673320070">"স্ক্রিন লক খুলুন"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"ফিঙ্গারপ্রিন্ট সেন্সর"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"যাচাই করিয়ে নিন"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"ডিভাইস আনলক করুন"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index a7f9068..8dee87a 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -1195,6 +1201,8 @@
<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>
<string name="accessibility_bouncer" msgid="5896923685673320070">"unos zaključavanja ekrana"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Senzor za otisak prsta"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"autentificiranje"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"pristup uređaju"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 4f055d4..f9d343f 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -303,10 +309,8 @@
<skip />
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Les funcions com Quick Share i Troba el meu dispositiu utilitzen el Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"El Bluetooth s\'activarà demà al matí"</string>
- <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
- <skip />
- <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
- <skip />
+ <string name="quick_settings_bluetooth_audio_sharing_button" msgid="7545274861795853838">"Comparteix l\'àudio"</string>
+ <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="3069309588231072128">"S\'està compartint l\'àudio"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> de bateria"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Àudio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Auriculars"</string>
@@ -1197,6 +1201,8 @@
<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 definida"</string>
<string name="accessibility_bouncer" msgid="5896923685673320070">"utilitza el bloqueig de pantalla"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Sensor d\'empremtes digitals"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"autenticar"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"accedir al dispositiu"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index e50fea5..3caa23d 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -1197,6 +1203,8 @@
<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>
<string name="accessibility_bouncer" msgid="5896923685673320070">"zadejte zámek obrazovky"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Snímač otisků prstů"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"ověříte"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"zadáte zařízení"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 310f2b1..5333768 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -303,10 +309,8 @@
<skip />
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Funktioner som f.eks. Quick Share og Find min enhed anvender Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth aktiveres i morgen tidlig"</string>
- <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
- <skip />
- <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
- <skip />
+ <string name="quick_settings_bluetooth_audio_sharing_button" msgid="7545274861795853838">"Del lyd"</string>
+ <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="3069309588231072128">"Deler lyd"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> batteri"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Lyd"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Headset"</string>
@@ -1197,6 +1201,8 @@
<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>
<string name="accessibility_bouncer" msgid="5896923685673320070">"angiv skærmlås"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Fingeraftrykssensor"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"godkende"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"få adgang til enheden"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 27f6b57..847e25f 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -303,10 +309,8 @@
<skip />
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Funktionen wie „Quick Share“ und „Mein Gerät finden“ verwenden Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth wird morgen früh aktiviert"</string>
- <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
- <skip />
- <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
- <skip />
+ <string name="quick_settings_bluetooth_audio_sharing_button" msgid="7545274861795853838">"Audioinhalte freigeben"</string>
+ <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="3069309588231072128">"Audioinhalte werden freigegeben"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Akkustand: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Headset"</string>
@@ -1197,6 +1201,8 @@
<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>
<string name="accessibility_bouncer" msgid="5896923685673320070">"Displaysperre eingeben"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Fingerabdrucksensor"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"Authentifizieren"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"Eingeben des Geräts"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index e2480b2e..80fe3d2 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -1197,6 +1203,8 @@
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Πατήστε για περισσότερες πληροφορίες."</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Δεν ορίστηκε ξυπνητ."</string>
<string name="accessibility_bouncer" msgid="5896923685673320070">"εισαγωγή κλειδώματος οθόνης"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Αισθητήρας δακτυλικών αποτυπωμάτων"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"έλεγχος ταυτότητας"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"εισαγωγή συσκευής"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 303e922..498031f 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -303,10 +309,8 @@
<skip />
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Features like Quick Share and Find My Device use Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth will turn on tomorrow morning"</string>
- <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
- <skip />
- <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
- <skip />
+ <string name="quick_settings_bluetooth_audio_sharing_button" msgid="7545274861795853838">"Share audio"</string>
+ <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="3069309588231072128">"Sharing audio"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> battery"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Headset"</string>
@@ -1197,6 +1201,8 @@
<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>
<string name="accessibility_bouncer" msgid="5896923685673320070">"enter screen lock"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Fingerprint sensor"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"Authenticate"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"enter device"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 042d06e..8975cbf 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -125,26 +125,19 @@
<string name="screenrecord_save_text" msgid="3008973099800840163">"Tap to view"</string>
<string name="screenrecord_save_error" msgid="5862648532560118815">"Error saving screen recording"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Error starting screen recording"</string>
- <!-- no translation found for screenrecord_stop_dialog_title (2685522129492260887) -->
- <skip />
- <!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
- <skip />
- <!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
- <skip />
- <!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
- <skip />
- <!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
- <skip />
- <!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
- <skip />
- <!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
- <skip />
- <!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
- <skip />
- <!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
- <skip />
- <!-- no translation found for close_dialog_button (4749497706540104133) -->
- <skip />
+ <string name="screenrecord_stop_dialog_title" msgid="2685522129492260887">"Stop recording screen?"</string>
+ <string name="screenrecord_stop_dialog_message" msgid="1926783607059442889">"You will stop recording your screen"</string>
+ <string name="screenrecord_stop_dialog_message_specific_app" msgid="5285148796772616326">"You will stop recording <b><xliff:g id="APP_NAME">%1$s</xliff:g></b>"</string>
+ <string name="screenrecord_stop_dialog_button" msgid="2883812564938194350">"Stop recording"</string>
+ <string name="share_to_app_stop_dialog_title" msgid="9212915050910250438">"Stop sharing screen?"</string>
+ <string name="share_to_app_stop_dialog_message" msgid="3181723638915877339">"You will stop sharing your screen"</string>
+ <string name="share_to_app_stop_dialog_message_specific_app" msgid="124371406810544777">"You will stop sharing <b><xliff:g id="APP_NAME">%1$s</xliff:g></b>"</string>
+ <string name="share_to_app_stop_dialog_button" msgid="6334056916284230217">"Stop sharing"</string>
+ <string name="cast_to_other_device_stop_dialog_title" msgid="1910372600290258193">"Stop casting screen?"</string>
+ <string name="cast_to_other_device_stop_dialog_message" msgid="1502520537030715412">"You will stop casting your screen"</string>
+ <string name="cast_to_other_device_stop_dialog_message_specific_app" msgid="4891536209254041850">"You will stop casting <b><xliff:g id="APP_NAME">%1$s</xliff:g></b>"</string>
+ <string name="cast_to_other_device_stop_dialog_button" msgid="6420183747435521834">"Stop casting"</string>
+ <string name="close_dialog_button" msgid="4749497706540104133">"Close"</string>
<string name="issuerecord_title" msgid="286627115110121849">"Issue Recorder"</string>
<string name="issuerecord_background_processing_label" msgid="1666840264959336876">"Processing issue recording"</string>
<string name="issuerecord_channel_description" msgid="6142326363431474632">"Ongoing notification for an issue collection session"</string>
@@ -155,8 +148,7 @@
<string name="issuerecord_save_error" msgid="6913040083446722726">"Error saving issue recording"</string>
<string name="issuerecord_start_error" msgid="3402782952722871190">"Error starting issue recording"</string>
<string name="immersive_cling_title" msgid="8372056499315585941">"Viewing full screen"</string>
- <!-- no translation found for immersive_cling_description (2717426731830851921) -->
- <skip />
+ <string name="immersive_cling_description" msgid="2717426731830851921">"To exit, swipe down from the top of your screen"</string>
<string name="immersive_cling_positive" msgid="3076681691468978568">"Got it"</string>
<string name="accessibility_back" msgid="6530104400086152611">"Back"</string>
<string name="accessibility_home" msgid="5430449841237966217">"Home"</string>
@@ -299,8 +291,7 @@
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Saved"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"disconnect"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"activate"</string>
- <!-- no translation found for turn_on_bluetooth_auto_tomorrow (3345758139235739006) -->
- <skip />
+ <string name="turn_on_bluetooth_auto_tomorrow" msgid="3345758139235739006">"Automatically turn on tomorrow"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Features like Quick Share and Find My Device use Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth will turn on tomorrow morning"</string>
<string name="quick_settings_bluetooth_audio_sharing_button" msgid="7545274861795853838">"Share audio"</string>
@@ -1195,6 +1186,8 @@
<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>
<string name="accessibility_bouncer" msgid="5896923685673320070">"enter screen lock"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Fingerprint sensor"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"authenticate"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"enter device"</string>
@@ -1345,14 +1338,10 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Collapse icon"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Expand icon"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"or"</string>
- <!-- no translation found for touchpad_tutorial_back_gesture_button (2746834288077265946) -->
- <skip />
- <!-- no translation found for touchpad_tutorial_home_gesture_button (7640544867625955304) -->
- <skip />
- <!-- no translation found for touchpad_tutorial_action_key_button (3220074511852927267) -->
- <skip />
- <!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
- <skip />
+ <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Back gesture"</string>
+ <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Home gesture"</string>
+ <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"Action key"</string>
+ <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Done"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Keyboard backlight"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Level %1$d of %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Home Controls"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 303e922..498031f 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -303,10 +309,8 @@
<skip />
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Features like Quick Share and Find My Device use Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth will turn on tomorrow morning"</string>
- <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
- <skip />
- <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
- <skip />
+ <string name="quick_settings_bluetooth_audio_sharing_button" msgid="7545274861795853838">"Share audio"</string>
+ <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="3069309588231072128">"Sharing audio"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> battery"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Headset"</string>
@@ -1197,6 +1201,8 @@
<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>
<string name="accessibility_bouncer" msgid="5896923685673320070">"enter screen lock"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Fingerprint sensor"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"Authenticate"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"enter device"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 303e922..498031f 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -303,10 +309,8 @@
<skip />
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Features like Quick Share and Find My Device use Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth will turn on tomorrow morning"</string>
- <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
- <skip />
- <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
- <skip />
+ <string name="quick_settings_bluetooth_audio_sharing_button" msgid="7545274861795853838">"Share audio"</string>
+ <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="3069309588231072128">"Sharing audio"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> battery"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Headset"</string>
@@ -1197,6 +1201,8 @@
<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>
<string name="accessibility_bouncer" msgid="5896923685673320070">"enter screen lock"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Fingerprint sensor"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"Authenticate"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"enter device"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 5a5af96..179b792 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -125,26 +125,19 @@
<string name="screenrecord_save_text" msgid="3008973099800840163">"Tap to view"</string>
<string name="screenrecord_save_error" msgid="5862648532560118815">"Error saving screen recording"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Error starting screen recording"</string>
- <!-- no translation found for screenrecord_stop_dialog_title (2685522129492260887) -->
- <skip />
- <!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
- <skip />
- <!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
- <skip />
- <!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
- <skip />
- <!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
- <skip />
- <!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
- <skip />
- <!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
- <skip />
- <!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
- <skip />
- <!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
- <skip />
- <!-- no translation found for close_dialog_button (4749497706540104133) -->
- <skip />
+ <string name="screenrecord_stop_dialog_title" msgid="2685522129492260887">"Stop recording screen?"</string>
+ <string name="screenrecord_stop_dialog_message" msgid="1926783607059442889">"You will stop recording your screen"</string>
+ <string name="screenrecord_stop_dialog_message_specific_app" msgid="5285148796772616326">"You will stop recording <b><xliff:g id="APP_NAME">%1$s</xliff:g></b>"</string>
+ <string name="screenrecord_stop_dialog_button" msgid="2883812564938194350">"Stop recording"</string>
+ <string name="share_to_app_stop_dialog_title" msgid="9212915050910250438">"Stop sharing screen?"</string>
+ <string name="share_to_app_stop_dialog_message" msgid="3181723638915877339">"You will stop sharing your screen"</string>
+ <string name="share_to_app_stop_dialog_message_specific_app" msgid="124371406810544777">"You will stop sharing <b><xliff:g id="APP_NAME">%1$s</xliff:g></b>"</string>
+ <string name="share_to_app_stop_dialog_button" msgid="6334056916284230217">"Stop sharing"</string>
+ <string name="cast_to_other_device_stop_dialog_title" msgid="1910372600290258193">"Stop casting screen?"</string>
+ <string name="cast_to_other_device_stop_dialog_message" msgid="1502520537030715412">"You will stop casting your screen"</string>
+ <string name="cast_to_other_device_stop_dialog_message_specific_app" msgid="4891536209254041850">"You will stop casting <b><xliff:g id="APP_NAME">%1$s</xliff:g></b>"</string>
+ <string name="cast_to_other_device_stop_dialog_button" msgid="6420183747435521834">"Stop casting"</string>
+ <string name="close_dialog_button" msgid="4749497706540104133">"Close"</string>
<string name="issuerecord_title" msgid="286627115110121849">"Issue Recorder"</string>
<string name="issuerecord_background_processing_label" msgid="1666840264959336876">"Processing issue recording"</string>
<string name="issuerecord_channel_description" msgid="6142326363431474632">"Ongoing notification for an issue collection session"</string>
@@ -155,8 +148,7 @@
<string name="issuerecord_save_error" msgid="6913040083446722726">"Error saving issue recording"</string>
<string name="issuerecord_start_error" msgid="3402782952722871190">"Error starting issue recording"</string>
<string name="immersive_cling_title" msgid="8372056499315585941">"Viewing full screen"</string>
- <!-- no translation found for immersive_cling_description (2717426731830851921) -->
- <skip />
+ <string name="immersive_cling_description" msgid="2717426731830851921">"To exit, swipe down from the top of your screen"</string>
<string name="immersive_cling_positive" msgid="3076681691468978568">"Got it"</string>
<string name="accessibility_back" msgid="6530104400086152611">"Back"</string>
<string name="accessibility_home" msgid="5430449841237966217">"Home"</string>
@@ -299,8 +291,7 @@
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Saved"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"disconnect"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"activate"</string>
- <!-- no translation found for turn_on_bluetooth_auto_tomorrow (3345758139235739006) -->
- <skip />
+ <string name="turn_on_bluetooth_auto_tomorrow" msgid="3345758139235739006">"Automatically turn on tomorrow"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Features like Quick Share and Find My Device use Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth will turn on tomorrow morning"</string>
<string name="quick_settings_bluetooth_audio_sharing_button" msgid="7545274861795853838">"Share audio"</string>
@@ -1195,6 +1186,8 @@
<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>
<string name="accessibility_bouncer" msgid="5896923685673320070">"enter screen lock"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Fingerprint sensor"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"authenticate"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"enter device"</string>
@@ -1345,14 +1338,10 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Collapse icon"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Expand icon"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"or"</string>
- <!-- no translation found for touchpad_tutorial_back_gesture_button (2746834288077265946) -->
- <skip />
- <!-- no translation found for touchpad_tutorial_home_gesture_button (7640544867625955304) -->
- <skip />
- <!-- no translation found for touchpad_tutorial_action_key_button (3220074511852927267) -->
- <skip />
- <!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
- <skip />
+ <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Back gesture"</string>
+ <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Home gesture"</string>
+ <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"Action key"</string>
+ <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Done"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Keyboard backlight"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Level %1$d of %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Home Controls"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index ce5bd5e..0cad6b7 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -1197,6 +1203,8 @@
<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 establecida"</string>
<string name="accessibility_bouncer" msgid="5896923685673320070">"ingresa el bloqueo pantalla"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Sensor de huellas dactilares"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"autenticar"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"ingresar al dispositivo"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 000db75..24638f5 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -303,10 +309,8 @@
<skip />
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Las funciones como Quick Share y Encontrar mi dispositivo usan Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"El Bluetooth se activará mañana por la mañana"</string>
- <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
- <skip />
- <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
- <skip />
+ <string name="quick_settings_bluetooth_audio_sharing_button" msgid="7545274861795853838">"Compartir audio"</string>
+ <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="3069309588231072128">"Compartiendo audio"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> de batería"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Auriculares"</string>
@@ -1197,6 +1201,8 @@
<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 puesta"</string>
<string name="accessibility_bouncer" msgid="5896923685673320070">"Poner bloqueo de pantalla"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Sensor de huellas digitales"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"autenticarte"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"acceder al dispositivo"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index fa10a8a..8169e82 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -1197,6 +1203,8 @@
<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>
<string name="accessibility_bouncer" msgid="5896923685673320070">"sisesta ekraanilukk"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Sõrmejäljeandur"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"autentimiseks"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"seadmesse sisenemiseks"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 960a92f..e9e8518 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -303,10 +309,8 @@
<skip />
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Quick Share, Bilatu nire gailua eta beste eginbide batzuek Bluetootha erabiltzen dute"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bihar goizean aktibatuko da Bluetootha"</string>
- <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
- <skip />
- <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
- <skip />
+ <string name="quick_settings_bluetooth_audio_sharing_button" msgid="7545274861795853838">"Partekatu audioa"</string>
+ <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="3069309588231072128">"Audioa partekatzen"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Bateria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audioa"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Entzungailua"</string>
@@ -1197,6 +1201,8 @@
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Informazio gehiago lortzeko, sakatu hau"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Alarmarik ez"</string>
<string name="accessibility_bouncer" msgid="5896923685673320070">"erabili pantailaren blokeoa"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Hatz-marken sentsorea"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"autentifikatu"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"sartu gailuan"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index f02c248..3e876ad 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -303,10 +309,8 @@
<skip />
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"ویژگیهایی مثل «همرسانی سریع» و «پیدا کردن دستگاهم» از بلوتوث استفاده میکنند"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"بلوتوث فردا صبح روشن خواهد شد"</string>
- <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
- <skip />
- <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
- <skip />
+ <string name="quick_settings_bluetooth_audio_sharing_button" msgid="7545274861795853838">"همرسانی صدا"</string>
+ <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="3069309588231072128">"درحال همرسانی صدا"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"شارژ باتری <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"صوت"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"هدست"</string>
@@ -1197,6 +1201,8 @@
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"برای اطلاعات بیشتر ضربه بزنید"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"هشداری تنظیم نشده"</string>
<string name="accessibility_bouncer" msgid="5896923685673320070">"وارد کردن قفل صفحه"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"حسگر اثرانگشت"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"اصالتسنجی کردن"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"وارد شدن به دستگاه"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 9a24082..2291d19 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -1197,6 +1203,8 @@
<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>
<string name="accessibility_bouncer" msgid="5896923685673320070">"käytä näytön lukitustapaa"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Sormenjälkitunnistin"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"todentaaksesi"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"avataksesi laitteen"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 77335de..fbd16d4 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -1197,6 +1203,8 @@
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Touchez pour en savoir plus"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Aucune alarme définie"</string>
<string name="accessibility_bouncer" msgid="5896923685673320070">"entrer verrouillage de l\'écran"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Capteur d\'empreintes digitales"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"authentifier"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"accéder à l\'appareil"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 98bfc72..55c39dc 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -1197,6 +1203,8 @@
<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>
<string name="accessibility_bouncer" msgid="5896923685673320070">"accéder au verrouillage de l\'écran"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Lecteur d\'empreinte digitale"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"s\'authentifier"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"accéder à l\'appareil"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 28cf92a..a85b9ec 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -1197,6 +1203,8 @@
<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>
<string name="accessibility_bouncer" msgid="5896923685673320070">"introducir o bloqueo de pantalla"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Sensor de impresión dixital"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"autenticar"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"poñer o dispositivo"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 2914bad..11846b3 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -303,10 +309,8 @@
<skip />
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"ક્વિક શેર અને Find My Device જેવી સુવિધાઓ બ્લૂટૂથનો ઉપયોગ કરે છે"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"બ્લૂટૂથ આવતીકાલે સવારે ચાલુ થશે"</string>
- <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
- <skip />
- <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
- <skip />
+ <string name="quick_settings_bluetooth_audio_sharing_button" msgid="7545274861795853838">"ઑડિયો શેર કરો"</string>
+ <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="3069309588231072128">"ઑડિયો શેર કરી રહ્યાં છીએ"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> બૅટરી"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"ઑડિયો"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"હૅડસેટ"</string>
@@ -1197,6 +1201,8 @@
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"વધુ માહિતી માટે ટૅપ કરો"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"કોઈ અલાર્મ સેટ નથી"</string>
<string name="accessibility_bouncer" msgid="5896923685673320070">"સ્ક્રીન લૉક દાખલ કરો"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"ફિંગરપ્રિન્ટ સેન્સર"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"ખાતરી કરો"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"ડિવાઇસ અનલૉક કરો"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index a6bc9b5..dcd3b6c 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -382,7 +388,7 @@
<string name="qs_record_issue_start" msgid="2979831312582567056">"शुरू करें"</string>
<string name="qs_record_issue_stop" msgid="3531747965741982657">"रोकें"</string>
<string name="qs_record_issue_bug_report" msgid="8229031766918650079">"गड़बड़ी की रिपोर्ट"</string>
- <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"आपके डिवाइस की कौनसी सुविधा पर असर पड़ा था?"</string>
+ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"आपके डिवाइस की किस सुविधा में समस्या आ रही थी?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"समस्या का टाइप चुनें"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"स्क्रीन रिकॉर्डर"</string>
<string name="performance" msgid="6552785217174378320">"परफ़ॉर्मेंस"</string>
@@ -393,7 +399,7 @@
<string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"ऐक्टिव"</string>
<string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"डिसकनेक्ट हो गया"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"कान की मशीनें"</string>
- <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"नया डिवाइस जोड़ें"</string>
+ <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"कान की नई मशीन जोड़ें"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"नया डिवाइस जोड़ने के लिए क्लिक करें"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"प्रीसेट अपडेट नहीं किया जा सका"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"प्रीसेट"</string>
@@ -1197,6 +1203,8 @@
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"ज़्यादा जानकारी के लिए टैप करें"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"कोई अलार्म सेट नहीं है"</string>
<string name="accessibility_bouncer" msgid="5896923685673320070">"स्क्रीन लॉक डालें"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"फ़िंगरप्रिंट सेंसर"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"पुष्टि करें"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"डिवाइस की होम स्क्रीन पर जाएं"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index ba82bdd..1eff7d4 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -1195,6 +1201,8 @@
<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>
<string name="accessibility_bouncer" msgid="5896923685673320070">"unesite zaključavanje zaslona"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Senzor otiska prsta"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"autentificirali"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"pristupili uređaju"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index bb22807..c0905b5 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -1197,6 +1203,8 @@
<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>
<string name="accessibility_bouncer" msgid="5896923685673320070">"képernyőzár megadása"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Ujjlenyomat-érzékelő"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"a hitelesítéshez"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"eszköz megadásához"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 14db87a..41593d8 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -1197,6 +1203,8 @@
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Հպեք՝ ավելին իմանալու համար"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Զարթուցիչ դրված չէ"</string>
<string name="accessibility_bouncer" msgid="5896923685673320070">"ապակողպել էկրանը"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Մատնահետքի սկաներ"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"նույնականացնել"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"նշել սարքը"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index f9f6370..831adf9 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -303,10 +309,8 @@
<skip />
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Fitur seperti Quick Share dan Temukan Perangkat Saya menggunakan Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth akan dinyalakan besok pagi"</string>
- <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
- <skip />
- <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
- <skip />
+ <string name="quick_settings_bluetooth_audio_sharing_button" msgid="7545274861795853838">"Bagikan audio"</string>
+ <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="3069309588231072128">"Berbagi audio"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Baterai <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Headset"</string>
@@ -1197,6 +1201,8 @@
<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>
<string name="accessibility_bouncer" msgid="5896923685673320070">"masukkan kunci layar"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Sensor sidik jari"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"autentikasi"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"masukkan perangkat"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 0266cb2..a73bd7a 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -303,10 +309,8 @@
<skip />
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Eiginleikar eins og Flýtideiling og Finna tækið mitt nota Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Kveikt verður á Bluetooth í fyrramálið"</string>
- <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
- <skip />
- <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
- <skip />
+ <string name="quick_settings_bluetooth_audio_sharing_button" msgid="7545274861795853838">"Deila hljóði"</string>
+ <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="3069309588231072128">"Deilir hljóði"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> rafhlöðuhleðsla"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Hljóð"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Höfuðtól"</string>
@@ -1197,6 +1201,8 @@
<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>
<string name="accessibility_bouncer" msgid="5896923685673320070">"sláðu inn skjálás"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Fingrafaralesari"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"auðkenna"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"opna tæki"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 9cc5124..a424f20 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -1195,6 +1201,8 @@
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Tocca per ulteriori informazioni"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Nessuna"</string>
<string name="accessibility_bouncer" msgid="5896923685673320070">"inserisci blocco schermo"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Sensore di impronte digitali"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"effettuare l\'autenticazione"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"accedere al dispositivo"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 734e7da..4e0977e 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -1197,6 +1203,8 @@
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"יש להקיש כדי להציג מידע נוסף"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"לא הוגדרה"</string>
<string name="accessibility_bouncer" msgid="5896923685673320070">"הזנת קוד נעילת המסך"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"חיישן טביעות אצבע"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"אימות"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"הזנת מכשיר"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 6e62972..6c8504bb 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -1197,6 +1203,8 @@
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"タップすると詳細が表示されます"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"アラーム未設定"</string>
<string name="accessibility_bouncer" msgid="5896923685673320070">"画面ロックを設定"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"指紋認証センサー"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"認証"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"デバイスを入力"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 5914f12..c21dc10 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -1197,6 +1203,8 @@
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"შეეხეთ მეტი ინფორმაციისთვის"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"მაღვიძარა არ არის"</string>
<string name="accessibility_bouncer" msgid="5896923685673320070">"ეკრანის დაბლოკვის შეყვანა"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"თითის ანაბეჭდის სენსორი"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"ავტორიზაცია"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"მოწყობილობის შეყვანა"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 40b9149..0a7b976 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -1197,6 +1203,8 @@
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Толығырақ ақпарат алу үшін түртіңіз."</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Оятқыш орнатылмаған."</string>
<string name="accessibility_bouncer" msgid="5896923685673320070">"экран құлпын енгізу"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Саусақ ізін оқу сканері"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"аутентификациялау"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"құрылғыны енгізу"</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 3836d7d..20a9ae5 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -1197,6 +1203,8 @@
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"ចុចដើម្បីទទួលបានព័ត៌មានបន្ថែម"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"មិនបានកំណត់ម៉ោងរោទ៍ទេ"</string>
<string name="accessibility_bouncer" msgid="5896923685673320070">"បញ្ចូលព័ត៌មានផ្ទៀងផ្ទាត់សម្រាប់ការចាក់សោអេក្រង់"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"ឧបករណ៍ចាប់ស្នាមម្រាមដៃ"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"ផ្ទៀងផ្ទាត់"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"បញ្ចូលឧបករណ៍"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 85d67cd..922075a 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -1197,6 +1203,8 @@
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"ಇನ್ನಷ್ಟು ಮಾಹಿತಿಗಾಗಿ ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"ಅಲಾರಾಂ ಸೆಟ್ ಆಗಿಲ್ಲ"</string>
<string name="accessibility_bouncer" msgid="5896923685673320070">"ಸ್ಕ್ರೀನ್ ಲಾಕ್ ನಮೂದಿಸಿ"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಸೆನ್ಸರ್"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"ದೃಢೀಕರಿಸಿ"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"ಸಾಧನವನ್ನು ಪ್ರವೇಶಿಸಿ"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 4c26ed2..496307a 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -1197,6 +1203,8 @@
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"탭하여 자세한 정보를 확인하세요."</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"설정된 알람 없음"</string>
<string name="accessibility_bouncer" msgid="5896923685673320070">"화면 잠금 입력"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"지문 센서"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"인증"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"기기 입력"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index ae91a7c..2e62142 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -1197,6 +1203,8 @@
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Кеңири маалымат алуу үчүн таптап коюңуз"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Ойготкуч коюлган жок"</string>
<string name="accessibility_bouncer" msgid="5896923685673320070">"экран кулпусун киргизүү"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Манжа изинин сенсору"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"аныктыгын текшерүү"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"түзмөккө кирүү"</string>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 30f8a65..fb3b377 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -1197,6 +1203,8 @@
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"ແຕະເພື່ອເບິ່ງຂໍ້ມູນເພີ່ມເຕີມ"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"ບໍ່ໄດ້ຕັ້ງໂມງປຸກ"</string>
<string name="accessibility_bouncer" msgid="5896923685673320070">"ໃສ່ຂໍ້ມູນການລັອກໜ້າຈໍ"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"ເຊັນເຊີລາຍນິ້ວມື"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"ພິສູດຢືນຢັນ"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"ເຂົ້າອຸປະກອນ"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 4fffb3d..cca7b7f 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -303,10 +309,8 @@
<skip />
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Tokioms funkcijoms kaip „Spartusis bendrinimas“ ir „Rasti įrenginį“ naudojamas „Bluetooth“ ryšys"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"„Bluetooth“ ryšys bus įjungtas rytoj ryte"</string>
- <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
- <skip />
- <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
- <skip />
+ <string name="quick_settings_bluetooth_audio_sharing_button" msgid="7545274861795853838">"Bendrinti garsą"</string>
+ <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="3069309588231072128">"Bendrinamas garsas"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Akumuliatorius: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Garsas"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Virtualiosios realybės įrenginys"</string>
@@ -1197,6 +1201,8 @@
<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>
<string name="accessibility_bouncer" msgid="5896923685673320070">"įvesti ekrano užraktą"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Kontrolinio kodo jutiklis"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"nustatytumėte tapatybę"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"pasiektumėte įrenginį"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 28b15d0..7c72c7e 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -1197,6 +1203,8 @@
<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>
<string name="accessibility_bouncer" msgid="5896923685673320070">"ievadīt ekrāna bloķēšanas informāciju"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Pirksta nospieduma sensors"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"veiktu autentificēšanu"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"izmantotu ierīci"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index bf71f8e..a8baf35 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -1197,6 +1203,8 @@
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Допрете за повеќе информации"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Не е поставен аларм"</string>
<string name="accessibility_bouncer" msgid="5896923685673320070">"внесете PIN/шема/лозинка"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Сензор за отпечатоци"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"автентицирате"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"внесете уред"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 2031af0..9f19680 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -1197,6 +1203,8 @@
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"കൂടുതൽ വിവരങ്ങൾക്ക് ടാപ്പ് ചെയ്യുക"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"അലാറം സജ്ജീകരിച്ചിട്ടില്ല"</string>
<string name="accessibility_bouncer" msgid="5896923685673320070">"സ്ക്രീൻ ലോക്ക് നൽകുക"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"ഫിംഗർപ്രിന്റ് സെൻസർ"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"പരിശോധിച്ചുറപ്പിക്കുക"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"ഉപകരണം നൽകുക"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 556d205..a6ab892 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -303,10 +309,8 @@
<skip />
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Түргэн хуваалцах, Миний төхөөрөмжийг олох зэрэг онцлогууд Bluetooth-г ашигладаг"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth-г маргааш өглөө асаана"</string>
- <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
- <skip />
- <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
- <skip />
+ <string name="quick_settings_bluetooth_audio_sharing_button" msgid="7545274861795853838">"Аудио хуваалцах"</string>
+ <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="3069309588231072128">"Аудио хуваалцаж байна"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> батарей"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Аудио"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Чихэвч"</string>
@@ -1197,6 +1201,8 @@
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Нэмэлт мэдээлэл авахын тулд товшино уу"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Сэрүүлэг тавиагүй"</string>
<string name="accessibility_bouncer" msgid="5896923685673320070">"дэлгэцийн түгжээ оруулах"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Хурууны хээ мэдрэгч"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"баталгаажуулах"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"төхөөрөмж оруулах"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index a009fe1..cc6e59a 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -303,10 +309,8 @@
<skip />
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"क्विक शेअर आणि Find My Device यांसारखी वैशिष्ट्ये ब्लूटूथ वापरतात"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"ब्लूटूथ उद्या सकाळी सुरू होईल"</string>
- <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
- <skip />
- <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
- <skip />
+ <string name="quick_settings_bluetooth_audio_sharing_button" msgid="7545274861795853838">"ऑडिओ शेअर करा"</string>
+ <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="3069309588231072128">"ऑडिओ शेअर करत आहे"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> बॅटरी"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"ऑडिओ"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"हेडसेट"</string>
@@ -1197,6 +1201,8 @@
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"अधिक माहितीसाठी टॅप करा"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"अलार्म सेट केला नाही"</string>
<string name="accessibility_bouncer" msgid="5896923685673320070">"स्क्रीन लॉक एंटर करा"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"फिंगरप्रिंट सेन्सर"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"ऑथेंटिकेट करा"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"डिव्हाइस एंटर करा"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 59c4071..ced6541 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -1197,6 +1203,8 @@
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Ketik untuk mendapatkan maklumat lanjut"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Tiada penggera"</string>
<string name="accessibility_bouncer" msgid="5896923685673320070">"masukkan kunci skrin"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Penderia cap jari"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"sahkan"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"akses peranti"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index d13ee63..eae8e1d 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -106,7 +106,7 @@
<string name="screenrecord_title" msgid="4257171601439507792">"ဖန်သားပြင်ရိုက်ကူးစက်"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"စကရင်ရိုက်ကူးမှု အပြီးသတ်နေသည်"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"ဖန်သားပြင် ရိုက်ကူးသည့် စက်ရှင်အတွက် ဆက်တိုက်လာနေသော အကြောင်းကြားချက်"</string>
- <string name="screenrecord_permission_dialog_title" msgid="303380743267672953">"ရိုက်သံဖမ်းခြင်း စတင်မလား။"</string>
+ <string name="screenrecord_permission_dialog_title" msgid="303380743267672953">"ရုပ်သံဖမ်းခြင်း စတင်မလား။"</string>
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="4152602778470789965">"ရုပ်သံဖမ်းနေစဉ် Android သည် သင့်ဖန်သားပြင်တွင် မြင်နိုင်သည့် (သို့) သင့်စက်တွင် ဖွင့်ထားသည့် အရာအားလုံးကို တွေ့နိုင်သည်။ စကားဝှက်၊ ငွေပေးချေမှု အချက်အလက်၊ မက်ဆေ့ဂျ်၊ ဓာတ်ပုံ၊ အသံနှင့် ဗီဒီယိုကဲ့သို့ အရာများကို ဂရုစိုက်ပါ။"</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="6818309727772146138">"အက်ပ်တစ်ခုကို ရုပ်သံဖမ်းနေစဉ် Android သည် ယင်းအက်ပ်တွင် ပြထားသည့် (သို့) ဖွင့်ထားသည့် အရာအားလုံးကို တွေ့နိုင်သည်။ ထို့ကြောင့် စကားဝှက်၊ ငွေပေးချေမှု အချက်အလက်၊ မက်ဆေ့ဂျ်၊ ဓာတ်ပုံ၊ အသံနှင့် ဗီဒီယိုကဲ့သို့ အရာများကို ဂရုစိုက်ပါ။"</string>
<string name="screenrecord_permission_dialog_continue" msgid="5811122652514424967">"ရုပ်သံ စဖမ်းရန်"</string>
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -303,10 +309,8 @@
<skip />
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"‘အမြန် မျှဝေပါ’ နှင့် Find My Device ကဲ့သို့ တူးလ်များသည် ဘလူးတုသ်သုံးသည်"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"မနက်ဖြန်နံနက်တွင် ဘလူးတုသ် ပွင့်ပါမည်"</string>
- <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
- <skip />
- <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
- <skip />
+ <string name="quick_settings_bluetooth_audio_sharing_button" msgid="7545274861795853838">"အသံမျှဝေရန်"</string>
+ <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="3069309588231072128">"အသံမျှဝေနေသည်"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> ဘက်ထရီ"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"အသံ"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"မိုက်ခွက်ပါနားကြပ်"</string>
@@ -1197,6 +1201,8 @@
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"နောက်ထပ်အချက်အလက်များအတွက် တို့ပါ"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"နှိုးစက်ပေးမထားပါ"</string>
<string name="accessibility_bouncer" msgid="5896923685673320070">"ဖန်သားပြင်လော့ခ် ထည့်ရန်"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"လက်ဗွေ အာရုံခံကိရိယာ"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"အထောက်အထားစိစစ်ရန်"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"စက်ပစ္စည်းသို့ ဝင်ရန်"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 91ef466..ebd37f4 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -303,10 +309,8 @@
<skip />
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Funksjoner som Quick Share og Finn enheten min bruker Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth slås på i morgen tidlig"</string>
- <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
- <skip />
- <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
- <skip />
+ <string name="quick_settings_bluetooth_audio_sharing_button" msgid="7545274861795853838">"Del lyd"</string>
+ <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="3069309588231072128">"Deler lyd"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> batteri"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Lyd"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Hodetelefoner"</string>
@@ -1197,6 +1201,8 @@
<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>
<string name="accessibility_bouncer" msgid="5896923685673320070">"legg inn skjermlåsen"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Fingeravtrykkssensor"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"autentiser"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"åpne enheten"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 10d64b7..f83f77c 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -1197,6 +1203,8 @@
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"थप जानकारी प्राप्त गर्न ट्याप गर्नुहोस्"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"अलार्म राखिएको छैन"</string>
<string name="accessibility_bouncer" msgid="5896923685673320070">"स्क्रिन लक हाल्नुहोस्"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"फिंगरप्रिन्ट सेन्सर"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"प्रमाणित गर्नुहोस्"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"डिभाइस हाल्नुहोस्"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index c990cab..110b59e 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -1197,6 +1203,8 @@
<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>
<string name="accessibility_bouncer" msgid="5896923685673320070">"schermvergrendeling invoeren"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Vingerafdruksensor"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"verifiëren"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"apparaat opgeven"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 49a3268..2c60c2b 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -1197,6 +1203,8 @@
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"ଅଧିକ ସୂଚନା ପାଇଁ ଟାପ୍ କରନ୍ତୁ"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"ଆଲାରାମ ସେଟ ହୋଇନାହିଁ"</string>
<string name="accessibility_bouncer" msgid="5896923685673320070">"ସ୍କ୍ରିନ ଲକ ଲେଖନ୍ତୁ"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"ଟିପଚିହ୍ନ ସେନ୍ସର୍"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"ପ୍ରମାଣୀକରଣ କରନ୍ତୁ"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"ଡିଭାଇସ୍ ବିଷୟରେ ସୂଚନା ଲେଖନ୍ତୁ"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 6a7e9e8..54a763d 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -1197,6 +1203,8 @@
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"ਹੋਰ ਜਾਣਕਾਰੀ ਲਈ ਟੈਪ ਕਰੋ"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"ਕੋਈ ਅਲਾਰਮ ਸੈੱਟ ਨਹੀਂ"</string>
<string name="accessibility_bouncer" msgid="5896923685673320070">"ਸਕ੍ਰੀਨ ਲਾਕ ਦਾਖਲ ਕਰੋ"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਸੈਂਸਰ"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"ਪ੍ਰਮਾਣਿਤ ਕਰੋ"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"ਡੀਵਾਈਸ ਵਿੱਚ ਦਾਖਲ ਹੋਵੋ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index c154fc9b..39e243d 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -303,10 +309,8 @@
<skip />
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Bluetootha używają funkcje takie jak szybkie udostępnianie czy Znajdź moje urządzenie"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth włączy się jutro rano"</string>
- <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
- <skip />
- <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
- <skip />
+ <string name="quick_settings_bluetooth_audio_sharing_button" msgid="7545274861795853838">"Udostępnij dźwięk"</string>
+ <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="3069309588231072128">"Udostępnia dźwięk"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> naładowania baterii"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Dźwięk"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Zestaw słuchawkowy"</string>
@@ -1197,6 +1201,8 @@
<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>
<string name="accessibility_bouncer" msgid="5896923685673320070">"Wprowadź blokadę ekranu"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Czytnik linii papilarnych"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"uwierzytelnij"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"otwórz urządzenie"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 2e64391..dc7d564 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -1197,6 +1203,8 @@
<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>
<string name="accessibility_bouncer" msgid="5896923685673320070">"inserir bloqueio de tela"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Sensor de impressão digital"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"autenticar"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"acessar o dispositivo"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index ca0f171..0b74941 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -1197,6 +1203,8 @@
<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 definido"</string>
<string name="accessibility_bouncer" msgid="5896923685673320070">"introduzir bloqueio de ecrã"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Sensor de impressões digitais"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"autenticar"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"entrar no dispositivo"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 2e64391..dc7d564 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -1197,6 +1203,8 @@
<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>
<string name="accessibility_bouncer" msgid="5896923685673320070">"inserir bloqueio de tela"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Sensor de impressão digital"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"autenticar"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"acessar o dispositivo"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 36457fd..f735be4 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -1197,6 +1203,8 @@
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Atinge pentru mai multe informații"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Nicio alarmă setată"</string>
<string name="accessibility_bouncer" msgid="5896923685673320070">"intră în blocarea ecranului"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Senzor de amprentă"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"autentifică-te"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"Accesează dispozitivul"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index fe0e8db..d7973fd 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -1197,6 +1203,8 @@
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Нажмите, чтобы узнать больше."</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Нет будильников"</string>
<string name="accessibility_bouncer" msgid="5896923685673320070">"разблокировать экран"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Сканер отпечатков пальцев"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"выполнить аутентификацию"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"указать устройство"</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 8357008..dac0c42 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -1197,6 +1203,8 @@
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"තවත් තොරතුරු සඳහා තට්ටු කරන්න"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"එලාම සකසා නැත"</string>
<string name="accessibility_bouncer" msgid="5896923685673320070">"තිර අගුල ඇතුළු කරන්න"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"ඇඟිලි සලකුණු සංවේදකය"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"සත්යාපනය කරන්න"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"උපාංගය ඇතුළු කරන්න"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 148b390..0014117 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -303,10 +309,8 @@
<skip />
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Funkcie ako Quick Share a Nájdi moje zariadenie používajú Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth sa zapne zajtra ráno"</string>
- <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
- <skip />
- <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
- <skip />
+ <string name="quick_settings_bluetooth_audio_sharing_button" msgid="7545274861795853838">"Zdieľať zvuk"</string>
+ <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="3069309588231072128">"Zdieľa sa zvuk"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Batéria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Zvuk"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Náhlavná súprava"</string>
@@ -1197,6 +1201,8 @@
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Klepnutím si zobrazíte ďalšie informácie"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Žiadny budík"</string>
<string name="accessibility_bouncer" msgid="5896923685673320070">"zadať zámku obrazovky"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Senzor odtlačkov prstov"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"overte"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"vstúpte do zariadenia"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 489551d..4428c0c 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -1197,6 +1203,8 @@
<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>
<string name="accessibility_bouncer" msgid="5896923685673320070">"odklenite zaslon"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Tipalo prstnih odtisov"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"preverjanje pristnosti"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"vstop v napravo"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 5b74b1e..537134d 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -303,10 +309,8 @@
<skip />
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Veçoritë e tilla si \"Ndarja e shpejtë\" dhe \"Gjej pajisjen time\" përdorin Bluetooth-in"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth-i do të aktivizohet nesër në mëngjes"</string>
- <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
- <skip />
- <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
- <skip />
+ <string name="quick_settings_bluetooth_audio_sharing_button" msgid="7545274861795853838">"Ndaj audion"</string>
+ <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="3069309588231072128">"Audioja po ndahet"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> bateri"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Kufje me mikrofon"</string>
@@ -1197,6 +1201,8 @@
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Trokit për më shumë informacione"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Nuk është caktuar asnjë alarm"</string>
<string name="accessibility_bouncer" msgid="5896923685673320070">"hyr te kyçja e ekranit"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Sensori i gjurmës së gishtit"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"për ta vërtetuar"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"për të hyrë në pajisje"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 1877274..1969746 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -303,10 +309,8 @@
<skip />
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Функције као што су Quick Share и Пронађи мој уређај користе Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth ће се укључити сутра ујутру"</string>
- <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
- <skip />
- <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
- <skip />
+ <string name="quick_settings_bluetooth_audio_sharing_button" msgid="7545274861795853838">"Дели звук"</string>
+ <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="3069309588231072128">"Дели се звук"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Ниво батерије је <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Аудио"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Слушалице"</string>
@@ -1197,6 +1201,8 @@
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Додирните за више информација"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Није подешен"</string>
<string name="accessibility_bouncer" msgid="5896923685673320070">"унесите откључавање екрана"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Сензор за отисак прста"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"потврдите идентитет"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"унесите уређај"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index dc4dea1..6f2c07b 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -1197,6 +1203,8 @@
<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>
<string name="accessibility_bouncer" msgid="5896923685673320070">"ange skärmlåset"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Fingeravtryckssensor"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"autentisera"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"ange enhet"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 7bfef43..a15d975 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -1197,6 +1203,8 @@
<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>
<string name="accessibility_bouncer" msgid="5896923685673320070">"weka kifunga skrini"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Kitambua alama ya kidole"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"thibitisha"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"weka kifaa"</string>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 6298363..c9e17ff 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -1197,6 +1203,8 @@
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"மேலும் தகவல்களுக்கு தட்டவும்"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"அலாரம் எதுவுமில்லை"</string>
<string name="accessibility_bouncer" msgid="5896923685673320070">"திரைப் பூட்டை உள்ளிடலாம்"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"கைரேகை சென்சார்"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"அங்கீகரி"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"சாதனத்தைத் திற"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index e3238fe..4917ff6 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -303,10 +309,8 @@
<skip />
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"క్విక్ షేర్, Find My Device వంటి ఫీచర్లు బ్లూటూత్ను ఉపయోగిస్తాయి"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"బ్లూటూత్ రేపు ఉదయం ఆన్ అవుతుంది"</string>
- <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
- <skip />
- <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
- <skip />
+ <string name="quick_settings_bluetooth_audio_sharing_button" msgid="7545274861795853838">"ఆడియోను షేర్ చేయండి"</string>
+ <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="3069309588231072128">"ఆడియోను షేర్ చేస్తున్నారు"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> బ్యాటరీ"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"ఆడియో"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"హెడ్సెట్"</string>
@@ -1197,6 +1201,8 @@
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"మరింత సమాచారం కోసం ట్యాప్ చేయండి"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"అలారం సెట్ చేయలేదు"</string>
<string name="accessibility_bouncer" msgid="5896923685673320070">"స్క్రీన్ లాక్ను ఎంటర్ చేయండి"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"వేలిముద్ర సెన్సార్"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"ప్రామాణీకరించండి"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"పరికరాన్ని ఎంటర్ చేయండి"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index d21bf5e..f4914f0 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -1197,6 +1203,8 @@
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"แตะดูข้อมูลเพิ่มเติม"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"ไม่มีการตั้งปลุก"</string>
<string name="accessibility_bouncer" msgid="5896923685673320070">"ป้อนข้อมูลการล็อกหน้าจอ"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"เซ็นเซอร์ลายนิ้วมือ"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"ตรวจสอบสิทธิ์"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"เข้าถึงอุปกรณ์"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index b63d282..89fa5ea 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -1197,6 +1203,8 @@
<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>
<string name="accessibility_bouncer" msgid="5896923685673320070">"ilagay ang lock ng screen"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Sensor para sa fingerprint"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"i-authenticate"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"ilagay ang device"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index f78afe4..bf6e6aa 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -1197,6 +1203,8 @@
<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 yok"</string>
<string name="accessibility_bouncer" msgid="5896923685673320070">"ekran kilidini gir"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Parmak izi sensörü"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"kimlik doğrulaması yapın"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"cihaz girin"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 46d0619..6206289 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -1197,6 +1203,8 @@
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Натисніть, щоб дізнатися більше"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Немає будильників"</string>
<string name="accessibility_bouncer" msgid="5896923685673320070">"показати способи розблокування екрана"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Сканер відбитків пальців"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"пройти автентифікацію"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"відкрити пристрій"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 38bddf7..0aab4ce 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -303,10 +309,8 @@
<skip />
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"فوری اشتراک اور \'میرا آلہ ڈھونڈیں\' جیسی خصوصیات بلوٹوتھ کا استعمال کرتی ہیں"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"بلوٹوتھ کل صبح آن ہو جائے گا"</string>
- <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
- <skip />
- <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
- <skip />
+ <string name="quick_settings_bluetooth_audio_sharing_button" msgid="7545274861795853838">"آڈیو کا اشتراک کریں"</string>
+ <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="3069309588231072128">"آڈیو کا اشتراک ہو رہا ہے"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> بیٹری"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"آڈیو"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"ہیڈ سیٹ"</string>
@@ -1201,6 +1205,8 @@
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"مزید معلومات کے لیے تھپتھپائیں"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"کوئی الارم سیٹ نہیں ہے"</string>
<string name="accessibility_bouncer" msgid="5896923685673320070">"اسکرین لاک درج کریں"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"فنگر پرنٹ سینسر"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"تصدیق کریں"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"آلہ درج کریں"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 52ecbc3..312737d 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -1197,6 +1203,8 @@
<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>
<string name="accessibility_bouncer" msgid="5896923685673320070">"ekran qulfini kiriting"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Barmoq izi skaneri"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"autentifikatsiya"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"qurilmani ochish"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 041da41..f578e14a 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -1197,6 +1203,8 @@
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Nhấn để biết thêm thông tin"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Chưa đặt chuông báo"</string>
<string name="accessibility_bouncer" msgid="5896923685673320070">"nhập phương thức mở khoá màn hình"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Cảm biến vân tay"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"xác thực"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"truy cập thiết bị"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 9df7a50..ae1f2b0 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -303,10 +309,8 @@
<skip />
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"快速分享、查找我的设备等功能会使用蓝牙"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"蓝牙将在明天早上开启"</string>
- <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
- <skip />
- <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
- <skip />
+ <string name="quick_settings_bluetooth_audio_sharing_button" msgid="7545274861795853838">"分享音频"</string>
+ <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="3069309588231072128">"正在分享音频"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> 的电量"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"音频"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"耳机"</string>
@@ -1197,6 +1201,8 @@
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"点按即可了解详情"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"未设置闹钟"</string>
<string name="accessibility_bouncer" msgid="5896923685673320070">"输入屏幕解锁信息"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"指纹传感器"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"身份验证"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"进入设备"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index fdb7759..35087f3 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -303,10 +309,8 @@
<skip />
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"「快速共享」和「尋找我的裝置」等功能都會使用藍牙"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"藍牙將於明天上午開啟"</string>
- <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
- <skip />
- <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
- <skip />
+ <string name="quick_settings_bluetooth_audio_sharing_button" msgid="7545274861795853838">"分享音訊"</string>
+ <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="3069309588231072128">"正在分享音訊"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"電量:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"音訊"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"耳機"</string>
@@ -1197,6 +1201,8 @@
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"輕按即可瞭解詳情"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"未設定鬧鐘"</string>
<string name="accessibility_bouncer" msgid="5896923685673320070">"輸入螢幕鎖定憑證"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"指紋感應器"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"驗證"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"進入裝置"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index cbeb38a..51fe3d7 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -303,10 +309,8 @@
<skip />
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"「快速分享」和「尋找我的裝置」等功能都需要使用藍牙技術"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"藍牙會在明天早上開啟"</string>
- <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
- <skip />
- <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
- <skip />
+ <string name="quick_settings_bluetooth_audio_sharing_button" msgid="7545274861795853838">"分享音訊"</string>
+ <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="3069309588231072128">"正在分享音訊"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"電量:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"音訊"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"耳機"</string>
@@ -1197,6 +1201,8 @@
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"輕觸即可瞭解詳情"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"未設定鬧鐘"</string>
<string name="accessibility_bouncer" msgid="5896923685673320070">"輸入螢幕鎖定憑證"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"指紋感應器"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"驗證"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"進入裝置"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 2117568..7b39f16 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -129,18 +129,24 @@
<skip />
<!-- no translation found for screenrecord_stop_dialog_message (1926783607059442889) -->
<skip />
+ <!-- no translation found for screenrecord_stop_dialog_message_specific_app (5285148796772616326) -->
+ <skip />
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
<skip />
+ <!-- no translation found for share_to_app_stop_dialog_message_specific_app (124371406810544777) -->
+ <skip />
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
<skip />
+ <!-- no translation found for cast_to_other_device_stop_dialog_message_specific_app (4891536209254041850) -->
+ <skip />
<!-- no translation found for cast_to_other_device_stop_dialog_button (6420183747435521834) -->
<skip />
<!-- no translation found for close_dialog_button (4749497706540104133) -->
@@ -1197,6 +1203,8 @@
<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>
<string name="accessibility_bouncer" msgid="5896923685673320070">"faka ukukhiya isikrini"</string>
+ <!-- no translation found for accessibility_side_fingerprint_indicator_label (1673807833352363712) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Inzwa yesigxivizo somunwe"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"gunyaza"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"faka idivayisi"</string>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index f8762f0..4ef9442 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -1049,4 +1049,7 @@
<!-- The width of the shortcut helper container, as a fraction of the screen's width. -->
<item name="shortcut_helper_screen_width_fraction" format="float" type="dimen">1.0</item>
+
+ <!-- Only applicable for dual shade - Allow Notifications/QS shade to anchor to the bottom. -->
+ <bool name="config_dualShadeAlignedToBottom">false</bool>
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index cf91326..40bdc3e 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -810,6 +810,8 @@
<dimen name="keyguard_smartspace_top_offset">12dp</dimen>
<!-- The amount to translate lockscreen elements on the GONE->AOD transition -->
<dimen name="keyguard_enter_from_top_translation_y">-100dp</dimen>
+ <!-- The amount to translate lockscreen elements on the GONE->AOD transition, on device fold -->
+ <dimen name="keyguard_enter_from_side_translation_x">-100dp</dimen>
<dimen name="notification_scrim_corner_radius">32dp</dimen>
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationController.java
index dafd5f8..030d147 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationController.java
@@ -72,6 +72,7 @@
private final Handler mHandler;
private boolean mIsFadeEffectEnabled;
private Runnable mSpringAnimationsEndAction;
+ private PointF mAnimationEndPosition = new PointF();
// Cache the animations state of {@link DynamicAnimation.TRANSLATION_X} and {@link
// DynamicAnimation.TRANSLATION_Y} to be well controlled by the touch handler
@@ -104,10 +105,12 @@
@Override
public void onRadiiAnimationStop() {}
});
+ mAnimationEndPosition = mMenuView.getMenuPosition();
}
void moveToPosition(PointF position) {
moveToPosition(position, /* animateMovement = */ false);
+ mAnimationEndPosition = position;
}
/* Moves position without updating underlying percentage position. Can be animated. */
@@ -129,6 +132,7 @@
} else {
DynamicAnimation.TRANSLATION_X.setValue(mMenuView, positionX);
}
+ mAnimationEndPosition.x = positionX;
}
void moveToPositionY(float positionY) {
@@ -144,6 +148,7 @@
} else {
DynamicAnimation.TRANSLATION_Y.setValue(mMenuView, positionY);
}
+ mAnimationEndPosition.y = positionY;
}
void moveToPositionYIfNeeded(float positionY) {
@@ -259,6 +264,9 @@
cancelAnimation(property);
mPositionAnimations.put(property, flingAnimation);
+ if (finalPosition != null) {
+ setAnimationEndPosition(property, finalPosition);
+ }
flingAnimation.start();
}
@@ -292,6 +300,7 @@
cancelAnimation(property);
mPositionAnimations.put(property, springAnimation);
+ setAnimationEndPosition(property, finalPosition);
springAnimation.animateToFinalPosition(finalPosition);
}
@@ -385,6 +394,21 @@
mPositionAnimations.get(property).cancel();
}
+ private void setAnimationEndPosition(
+ DynamicAnimation.ViewProperty property, Float endPosition) {
+ if (property.equals(DynamicAnimation.TRANSLATION_X)) {
+ mAnimationEndPosition.x = endPosition;
+ }
+ if (property.equals(DynamicAnimation.TRANSLATION_Y)) {
+ mAnimationEndPosition.y = endPosition;
+ }
+ }
+
+ void skipAnimations() {
+ cancelAnimations();
+ moveToPosition(mAnimationEndPosition, false);
+ }
+
@VisibleForTesting
DynamicAnimation getAnimation(DynamicAnimation.ViewProperty property) {
return mPositionAnimations.getOrDefault(property, null);
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java
index 0c67c50..ae9775a0 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java
@@ -334,6 +334,7 @@
mDragToInteractView.updateResources();
mDismissView.updateResources();
mDragToInteractAnimationController.updateResources();
+ mMenuAnimationController.skipAnimations();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractor.kt
index 20d8a2a..fd540c4 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractor.kt
@@ -22,6 +22,7 @@
import com.android.systemui.communal.data.repository.CommunalSceneRepository
import com.android.systemui.communal.domain.model.CommunalTransitionProgressModel
import com.android.systemui.communal.shared.model.CommunalScenes
+import com.android.systemui.communal.shared.model.CommunalTransitionKeys
import com.android.systemui.communal.shared.model.EditModeState
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
@@ -60,14 +61,14 @@
communalSceneRepository.snapToScene(newScene, delayMillis)
}
- /** Immediately snaps to the new scene when activity is started. */
- fun snapToSceneForActivityStart(newScene: SceneKey, delayMillis: Long = 0) {
+ /** Changes to Blank scene when starting an activity after dismissing keyguard. */
+ fun changeSceneForActivityStartOnDismissKeyguard() {
// skip if we're starting edit mode activity, as it will be handled later by changeScene
// with transition key [CommunalTransitionKeys.ToEditMode].
if (_editModeState.value == EditModeState.STARTING) {
return
}
- snapToScene(newScene, delayMillis)
+ changeScene(CommunalScenes.Blank, CommunalTransitionKeys.SimpleFade)
}
/**
@@ -144,8 +145,14 @@
*
* This flow will be true during any transition and when idle on the communal scene.
*/
- val isCommunalVisible: Flow<Boolean> =
- transitionState.map {
- !(it is ObservableTransitionState.Idle && it.currentScene == CommunalScenes.Blank)
- }
+ val isCommunalVisible: StateFlow<Boolean> =
+ transitionState
+ .map {
+ !(it is ObservableTransitionState.Idle && it.currentScene == CommunalScenes.Blank)
+ }
+ .stateIn(
+ scope = applicationScope,
+ started = SharingStarted.WhileSubscribed(),
+ initialValue = false,
+ )
}
diff --git a/packages/SystemUI/src/com/android/systemui/deviceconfig/data/repository/DeviceConfigRepository.kt b/packages/SystemUI/src/com/android/systemui/deviceconfig/data/repository/DeviceConfigRepository.kt
new file mode 100644
index 0000000..250b432
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/deviceconfig/data/repository/DeviceConfigRepository.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.deviceconfig.data.repository
+
+import android.provider.DeviceConfig
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.util.DeviceConfigProxy
+import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow
+import java.util.concurrent.Executor
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flowOn
+
+@SysUISingleton
+class DeviceConfigRepository
+@Inject
+constructor(
+ @Background private val backgroundExecutor: Executor,
+ @Background private val backgroundDispatcher: CoroutineDispatcher,
+ private val dataSource: DeviceConfigProxy,
+) {
+
+ fun property(namespace: String, name: String, default: Boolean): Flow<Boolean> {
+ return conflatedCallbackFlow {
+ val listener = { properties: DeviceConfig.Properties ->
+ if (properties.keyset.contains(name)) {
+ trySend(properties.getBoolean(name, default))
+ }
+ }
+
+ dataSource.addOnPropertiesChangedListener(
+ namespace,
+ backgroundExecutor,
+ listener,
+ )
+ trySend(dataSource.getBoolean(namespace, name, default))
+
+ awaitClose { dataSource.removeOnPropertiesChangedListener(listener) }
+ }
+ .flowOn(backgroundDispatcher)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/deviceconfig/domain/interactor/DeviceConfigInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceconfig/domain/interactor/DeviceConfigInteractor.kt
new file mode 100644
index 0000000..d04f8bc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/deviceconfig/domain/interactor/DeviceConfigInteractor.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.deviceconfig.domain.interactor
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.deviceconfig.data.repository.DeviceConfigRepository
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+
+@SysUISingleton
+class DeviceConfigInteractor
+@Inject
+constructor(
+ private val repository: DeviceConfigRepository,
+) {
+
+ fun property(namespace: String, name: String, default: Boolean): Flow<Boolean> {
+ return repository.property(namespace, name, default)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt
index 9d6c2bf..d4a166f 100644
--- a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt
@@ -47,7 +47,6 @@
import kotlinx.coroutines.flow.filterIsInstance
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.scan
import kotlinx.coroutines.flow.shareIn
@@ -155,10 +154,11 @@
is DisplayEvent.Changed -> previousIds + id
}
}
- .shareIn(
+ .distinctUntilChanged()
+ .stateIn(
bgApplicationScope,
- started = SharingStarted.WhileSubscribed(),
- replay = 1
+ SharingStarted.WhileSubscribed(),
+ emptySet(),
)
} else {
oldEnabledDisplays.map { enabledDisplaysSet ->
@@ -177,7 +177,8 @@
enabledDisplayIds
.mapElementsLazily { displayId -> getDisplay(displayId) }
.flowOn(backgroundCoroutineDispatcher)
- .debugLog("enabledDisplayIds")
+ .debugLog("enabledDisplays")
+ .stateIn(bgApplicationScope, SharingStarted.WhileSubscribed(), emptySet())
} else {
oldEnabledDisplays
}
@@ -355,20 +356,31 @@
* [createValue] returns a null element, it will not be added in the output set.
*/
private fun <T, V> Flow<Set<T>>.mapElementsLazily(createValue: (T) -> V?): Flow<Set<V>> {
- var initialSet = emptySet<T>()
- val currentMap = mutableMapOf<T, V>()
- var resultSet = emptySet<V>()
- return onEach { currentSet ->
- val removed = initialSet - currentSet
- val added = currentSet - initialSet
- if (added.isNotEmpty() || removed.isNotEmpty()) {
- added.forEach { key: T -> createValue(key)?.let { currentMap[key] = it } }
- removed.forEach { key: T -> currentMap.remove(key) }
- resultSet = currentMap.values.toSet() // Creates a **copy** of values
+ data class State<T, V>(
+ val previousSet: Set<T>,
+ // Caches T values from the previousSet that were already converted to V
+ val valueMap: Map<T, V>,
+ val resultSet: Set<V>
+ )
+
+ val initialState = State(emptySet<T>(), emptyMap(), emptySet<V>())
+
+ return this.scan(initialState) { state, currentSet ->
+ if (currentSet == state.previousSet) {
+ state
+ } else {
+ val removed = state.previousSet - currentSet
+ val added = currentSet - state.previousSet
+ val newMap = state.valueMap.toMutableMap()
+
+ added.forEach { key -> createValue(key)?.let { newMap[key] = it } }
+ removed.forEach { key -> newMap.remove(key) }
+
+ val resultSet = newMap.values.toSet()
+ State(currentSet, newMap, resultSet)
}
- initialSet = currentSet
}
- .map { resultSet }
+ .map { it.resultSet }
}
private companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffect.kt b/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffect.kt
index be4c903..7b5139a 100644
--- a/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffect.kt
+++ b/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffect.kt
@@ -97,14 +97,15 @@
State.IDLE -> {
setState(State.TIMEOUT_WAIT)
}
- State.RUNNING_BACKWARDS -> callback?.onCancelAnimator()
+ State.RUNNING_BACKWARDS_FROM_UP,
+ State.RUNNING_BACKWARDS_FROM_CANCEL -> callback?.onCancelAnimator()
else -> {}
}
}
fun handleActionUp() {
if (state == State.RUNNING_FORWARD) {
- setState(State.RUNNING_BACKWARDS)
+ setState(State.RUNNING_BACKWARDS_FROM_UP)
callback?.onReverseAnimator()
}
}
@@ -113,7 +114,7 @@
when (state) {
State.TIMEOUT_WAIT -> setState(State.IDLE)
State.RUNNING_FORWARD -> {
- setState(State.RUNNING_BACKWARDS)
+ setState(State.RUNNING_BACKWARDS_FROM_CANCEL)
callback?.onReverseAnimator()
}
else -> {}
@@ -127,20 +128,24 @@
/** This function is called both when an animator completes or gets cancelled */
fun handleAnimationComplete() {
- if (state == State.RUNNING_FORWARD) {
- setState(State.IDLE)
- vibrate(snapEffect)
- if (keyguardStateController.isUnlocked) {
- callback?.onPrepareForLaunch()
- qsTile?.longClick(expandable)
- } else {
- callback?.onResetProperties()
- qsTile?.longClick(expandable)
+ when (state) {
+ State.RUNNING_FORWARD -> {
+ setState(State.IDLE)
+ vibrate(snapEffect)
+ if (keyguardStateController.isUnlocked) {
+ qsTile?.longClick(expandable)
+ } else {
+ callback?.onResetProperties()
+ qsTile?.longClick(expandable)
+ }
}
- }
- if (state != State.TIMEOUT_WAIT) {
- // This will happen if the animator did not finish by being cancelled
- setState(State.IDLE)
+ State.RUNNING_BACKWARDS_FROM_UP -> {
+ setState(State.IDLE)
+ callback?.onEffectFinishedReversing()
+ qsTile?.click(expandable)
+ }
+ State.RUNNING_BACKWARDS_FROM_CANCEL -> setState(State.IDLE)
+ else -> {}
}
}
@@ -191,20 +196,23 @@
enum class State {
IDLE, /* The effect is idle waiting for touch input */
- TIMEOUT_WAIT, /* The effect is waiting for a [PRESSED_TIMEOUT] period */
+ TIMEOUT_WAIT, /* The effect is waiting for a tap timeout period */
RUNNING_FORWARD, /* The effect is running normally */
- RUNNING_BACKWARDS, /* The effect was interrupted and is now running backwards */
+ /* The effect was interrupted by an ACTION_UP and is now running backwards */
+ RUNNING_BACKWARDS_FROM_UP,
+ /* The effect was interrupted by an ACTION_CANCEL and is now running backwards */
+ RUNNING_BACKWARDS_FROM_CANCEL,
}
/** Callbacks to notify view and animator actions */
interface Callback {
- /** Prepare for an activity launch */
- fun onPrepareForLaunch()
-
/** Reset the tile visual properties */
fun onResetProperties()
+ /** Event where the effect completed by being reversed */
+ fun onEffectFinishedReversing()
+
/** Start the effect animator */
fun onStartAnimator()
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/view/ShortcutHelperActivity.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/view/ShortcutHelperActivity.kt
index 04fa749..8706280 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/view/ShortcutHelperActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/view/ShortcutHelperActivity.kt
@@ -123,7 +123,7 @@
resources.getFloat(R.dimen.shortcut_helper_screen_width_fraction)
// maxWidth needs to be set before the sheet is drawn, otherwise the call will have no
// effect.
- val screenWidth = resources.displayMetrics.widthPixels
+ val screenWidth = windowManager.maximumWindowMetrics.bounds.width()
bottomSheetBehavior.maxWidth = (sheetScreenWidthFraction * screenWidth).toInt()
}
@@ -132,7 +132,7 @@
val safeDrawingInsets = insets.safeDrawing
// Make sure the bottom sheet is not covered by the status bar.
bottomSheetBehavior.maxHeight =
- resources.displayMetrics.heightPixels - safeDrawingInsets.top
+ windowManager.maximumWindowMetrics.bounds.height() - safeDrawingInsets.top
// Make sure the contents inside of the bottom sheet are not hidden by system bars, or
// cutouts.
bottomSheet.updatePadding(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
index d508b2b..cdf3b06 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
@@ -78,6 +78,8 @@
val keyguardAlpha: StateFlow<Float>
+ val panelAlpha: MutableStateFlow<Float>
+
/**
* Observable for whether the keyguard is showing.
*
@@ -250,6 +252,9 @@
/** Sets the current amount of alpha that should be used for rendering the keyguard. */
fun setKeyguardAlpha(alpha: Float)
+ /** Temporary shim for fading out content when the brightness slider is used */
+ fun setPanelAlpha(alpha: Float)
+
/** Whether the device is actively dreaming */
fun setDreaming(isDreaming: Boolean)
@@ -338,6 +343,8 @@
private val _keyguardAlpha = MutableStateFlow(1f)
override val keyguardAlpha = _keyguardAlpha.asStateFlow()
+ override val panelAlpha: MutableStateFlow<Float> = MutableStateFlow(1f)
+
private val _clockShouldBeCentered = MutableStateFlow(true)
override val clockShouldBeCentered: Flow<Boolean> = _clockShouldBeCentered.asStateFlow()
@@ -659,6 +666,10 @@
_keyguardAlpha.value = alpha
}
+ override fun setPanelAlpha(alpha: Float) {
+ panelAlpha.value = alpha
+ }
+
override fun setDreaming(isDreaming: Boolean) {
this.isDreaming.value = isDreaming
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
index f30eef0..35a2d58 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
@@ -34,6 +34,7 @@
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.power.domain.interactor.PowerInteractor
+import com.android.systemui.power.shared.model.WakeSleepReason.FOLD
import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.data.repository.ShadeRepository
@@ -368,7 +369,12 @@
// being delayed in KeyguardViewMediator
KeyguardState.DREAMING -> TO_DREAMING_DURATION + 100.milliseconds
KeyguardState.OCCLUDED -> TO_OCCLUDED_DURATION
- KeyguardState.AOD -> TO_AOD_DURATION
+ KeyguardState.AOD ->
+ if (powerInteractor.detailedWakefulness.value.lastSleepReason == FOLD) {
+ TO_AOD_FOLD_DURATION
+ } else {
+ TO_AOD_DURATION
+ }
KeyguardState.DOZING -> TO_DOZING_DURATION
KeyguardState.DREAMING_LOCKSCREEN_HOSTED -> TO_DREAMING_HOSTED_DURATION
KeyguardState.GLANCEABLE_HUB -> TO_GLANCEABLE_HUB_DURATION
@@ -385,6 +391,7 @@
val TO_DREAMING_HOSTED_DURATION = 933.milliseconds
val TO_OCCLUDED_DURATION = 450.milliseconds
val TO_AOD_DURATION = 500.milliseconds
+ val TO_AOD_FOLD_DURATION = 1100.milliseconds
val TO_PRIMARY_BOUNCER_DURATION = DEFAULT_DURATION
val TO_GONE_DURATION = 633.milliseconds
val TO_GLANCEABLE_HUB_DURATION = 1.seconds
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
index ef96be0..ab1194e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
@@ -321,6 +321,10 @@
@Deprecated("Use the relevant TransitionViewModel")
val keyguardAlpha: Flow<Float> = repository.keyguardAlpha
+ /** Temporary shim for fading out content when the brightness slider is used */
+ @Deprecated("SceneContainer uses NotificationStackAppearanceInteractor")
+ val panelAlpha: StateFlow<Float> = repository.panelAlpha.asStateFlow()
+
/**
* When the lockscreen can be dismissed, emit an alpha value as the user swipes up. This is
* useful just before the code commits to moving to GONE.
@@ -458,6 +462,10 @@
repository.setKeyguardAlpha(alpha)
}
+ fun setPanelAlpha(alpha: Float) {
+ repository.setPanelAlpha(alpha)
+ }
+
fun setAnimateDozingTransitions(animate: Boolean) {
repository.setAnimateDozingTransitions(animate)
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/ToAodFoldTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/ToAodFoldTransitionInteractor.kt
index 6729246..21b9e53 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/ToAodFoldTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/ToAodFoldTransitionInteractor.kt
@@ -16,30 +16,17 @@
package com.android.systemui.keyguard.domain.interactor
-import android.animation.ValueAnimator
import android.view.ViewGroup
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
-import com.android.systemui.keyguard.shared.model.TransitionInfo
-import com.android.systemui.keyguard.shared.model.TransitionModeOnCanceled
import com.android.systemui.shade.NotificationPanelViewController
import com.android.systemui.shade.ShadeFoldAnimator
import javax.inject.Inject
-import kotlinx.coroutines.CoroutineDispatcher
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.launch
@SysUISingleton
class ToAodFoldTransitionInteractor
@Inject
constructor(
private val keyguardClockInteractor: KeyguardClockInteractor,
- private val transitionInteractor: KeyguardTransitionInteractor,
- private val transitionRepository: KeyguardTransitionRepository,
- @Application private val mainScope: CoroutineScope,
- @Main private val mainDispatcher: CoroutineDispatcher,
) {
private var parentAnimator: NotificationPanelViewController.ShadeFoldAnimatorImpl? = null
@@ -50,7 +37,6 @@
get() = throw NotImplementedError("Deprecated. Do not call.")
override fun prepareFoldToAodAnimation() {
- forceToAod()
parentAnimator?.prepareFoldToAodAnimation()
}
@@ -78,21 +64,6 @@
parentAnimator as? NotificationPanelViewController.ShadeFoldAnimatorImpl?
}
- /** Forces the keyguard into AOD or Doze */
- private fun forceToAod() {
- mainScope.launch(mainDispatcher) {
- transitionRepository.startTransition(
- TransitionInfo(
- "$TAG (Fold transition triggered)",
- transitionInteractor.getCurrentState(),
- transitionInteractor.asleepKeyguardState.value,
- ValueAnimator().apply { duration = 0 },
- TransitionModeOnCanceled.LAST_VALUE,
- )
- )
- }
- }
-
companion object {
private val TAG = ToAodFoldTransitionInteractor::class.simpleName!!
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt
index d9a6d64..62b4782 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt
@@ -55,6 +55,7 @@
private val keyguardInteractor: KeyguardInteractor,
private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
private val goneToAodTransitionViewModel: GoneToAodTransitionViewModel,
+ private val lockscreenToAodTransitionViewModel: LockscreenToAodTransitionViewModel,
private val aodToLockscreenTransitionViewModel: AodToLockscreenTransitionViewModel,
private val occludedToLockscreenTransitionViewModel: OccludedToLockscreenTransitionViewModel,
private val keyguardClockViewModel: KeyguardClockViewModel,
@@ -74,13 +75,30 @@
burnInParams
}
return configurationInteractor
- .dimensionPixelSize(R.dimen.keyguard_enter_from_top_translation_y)
- .flatMapLatest { enterFromTopAmount ->
+ .dimensionPixelSize(
+ setOf(
+ R.dimen.keyguard_enter_from_top_translation_y,
+ R.dimen.keyguard_enter_from_side_translation_x,
+ )
+ )
+ .flatMapLatest { dimens ->
combine(
keyguardInteractor.keyguardTranslationY.onStart { emit(0f) },
burnIn(params).onStart { emit(BurnInModel()) },
goneToAodTransitionViewModel
- .enterFromTopTranslationY(enterFromTopAmount)
+ .enterFromTopTranslationY(
+ dimens[R.dimen.keyguard_enter_from_top_translation_y]!!
+ )
+ .onStart { emit(StateToValue()) },
+ goneToAodTransitionViewModel
+ .enterFromSideTranslationX(
+ dimens[R.dimen.keyguard_enter_from_side_translation_x]!!
+ )
+ .onStart { emit(StateToValue()) },
+ lockscreenToAodTransitionViewModel
+ .enterFromSideTranslationX(
+ dimens[R.dimen.keyguard_enter_from_side_translation_x]!!
+ )
.onStart { emit(StateToValue()) },
occludedToLockscreenTransitionViewModel.lockscreenTranslationY.onStart {
emit(0f)
@@ -88,21 +106,31 @@
aodToLockscreenTransitionViewModel.translationY(params.translationY).onStart {
emit(StateToValue())
},
- ) {
- keyguardTranslationY,
- burnInModel,
- goneToAod,
- occludedToLockscreen,
- aodToLockscreen ->
+ ) { flows ->
+ val keyguardTranslationY = flows[0] as Float
+ val burnInModel = flows[1] as BurnInModel
+ val goneToAodTranslationY = flows[2] as StateToValue
+ val goneToAodTranslationX = flows[3] as StateToValue
+ val lockscreenToAodTranslationX = flows[4] as StateToValue
+ val occludedToLockscreen = flows[5] as Float
+ val aodToLockscreen = flows[6] as StateToValue
+
val translationY =
if (aodToLockscreen.transitionState.isTransitioning()) {
aodToLockscreen.value ?: 0f
- } else if (goneToAod.transitionState.isTransitioning()) {
- (goneToAod.value ?: 0f) + burnInModel.translationY
+ } else if (goneToAodTranslationY.transitionState.isTransitioning()) {
+ (goneToAodTranslationY.value ?: 0f) + burnInModel.translationY
} else {
burnInModel.translationY + occludedToLockscreen + keyguardTranslationY
}
- burnInModel.copy(translationY = translationY.toInt())
+ val translationX =
+ burnInModel.translationX +
+ (goneToAodTranslationX.value ?: 0f) +
+ (lockscreenToAodTranslationX.value ?: 0f)
+ burnInModel.copy(
+ translationX = translationX.toInt(),
+ translationY = translationY.toInt(),
+ )
}
}
.distinctUntilChanged()
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModel.kt
index 74f7d75..2bc8e51 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModel.kt
@@ -26,13 +26,17 @@
import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
import com.android.systemui.keyguard.ui.StateToValue
import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition
+import com.android.systemui.power.domain.interactor.PowerInteractor
+import com.android.systemui.power.shared.model.WakeSleepReason.FOLD
import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.transform
/** Breaks down GONE->AOD transition into discrete steps for corresponding views to consume. */
@ExperimentalCoroutinesApi
@@ -41,6 +45,7 @@
@Inject
constructor(
deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor,
+ private val powerInteractor: PowerInteractor,
animationFlow: KeyguardTransitionAnimationFlow,
) : DeviceEntryIconTransition {
@@ -56,13 +61,38 @@
/** y-translation from the top of the screen for AOD */
fun enterFromTopTranslationY(translatePx: Int): Flow<StateToValue> {
- return transitionAnimation.sharedFlowWithState(
- startTime = 600.milliseconds,
- duration = 500.milliseconds,
- onStep = { translatePx + it * -translatePx },
- onFinish = { 0f },
- interpolator = EMPHASIZED_DECELERATE,
- )
+ return transitionAnimation
+ .sharedFlowWithState(
+ startTime = 600.milliseconds,
+ duration = 500.milliseconds,
+ onStep = { translatePx + it * -translatePx },
+ onFinish = { 0f },
+ interpolator = EMPHASIZED_DECELERATE,
+ )
+ .sample(powerInteractor.detailedWakefulness, ::Pair)
+ .transform { (stateToValue, wakefulness) ->
+ if (wakefulness.lastSleepReason != FOLD) {
+ emit(stateToValue)
+ }
+ }
+ }
+
+ /** x-translation from the side of the screen for fold animation */
+ fun enterFromSideTranslationX(translatePx: Int): Flow<StateToValue> {
+ return transitionAnimation
+ .sharedFlowWithState(
+ startTime = 500.milliseconds,
+ duration = 600.milliseconds,
+ onStep = { translatePx + it * -translatePx },
+ onFinish = { 0f },
+ interpolator = EMPHASIZED_DECELERATE,
+ )
+ .sample(powerInteractor.detailedWakefulness, ::Pair)
+ .transform { (stateToValue, wakefulness) ->
+ if (wakefulness.lastSleepReason == FOLD) {
+ emit(stateToValue)
+ }
+ }
}
val notificationAlpha: Flow<Float> =
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
index aefff7d..d7ac976 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
@@ -251,6 +251,7 @@
goneToDreamingTransitionViewModel.lockscreenAlpha,
goneToLockscreenTransitionViewModel.lockscreenAlpha,
lockscreenToAodTransitionViewModel.lockscreenAlpha(viewState),
+ lockscreenToAodTransitionViewModel.lockscreenAlphaOnFold,
lockscreenToDozingTransitionViewModel.lockscreenAlpha,
lockscreenToDreamingTransitionViewModel.lockscreenAlpha,
lockscreenToGlanceableHubTransitionViewModel.keyguardAlpha,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModel.kt
index 8b5b347..5408428 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModel.kt
@@ -17,6 +17,7 @@
package com.android.systemui.keyguard.ui.viewmodel
import android.util.MathUtils
+import com.android.app.animation.Interpolators.EMPHASIZED_DECELERATE
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor
import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor
@@ -24,12 +25,17 @@
import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
+import com.android.systemui.keyguard.ui.StateToValue
import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition
+import com.android.systemui.power.domain.interactor.PowerInteractor
+import com.android.systemui.power.shared.model.WakeSleepReason.FOLD
+import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.transform
/**
* Breaks down LOCKSCREEN->AOD transition into discrete steps for corresponding views to consume.
@@ -40,6 +46,7 @@
@Inject
constructor(
deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor,
+ private val powerInteractor: PowerInteractor,
shadeDependentFlows: ShadeDependentFlows,
animationFlow: KeyguardTransitionAnimationFlow,
) : DeviceEntryIconTransition {
@@ -50,6 +57,12 @@
edge = Edge.create(from = LOCKSCREEN, to = AOD),
)
+ private val transitionAnimationOnFold =
+ animationFlow.setup(
+ duration = FromLockscreenTransitionInteractor.TO_AOD_FOLD_DURATION,
+ edge = Edge.create(from = LOCKSCREEN, to = AOD),
+ )
+
val deviceEntryBackgroundViewAlpha: Flow<Float> =
shadeDependentFlows.transitionFlow(
flowWhenShadeIsExpanded = transitionAnimation.immediatelyTransitionTo(0f),
@@ -71,11 +84,64 @@
fun lockscreenAlpha(viewState: ViewStateAccessor): Flow<Float> {
var startAlpha = 1f
- return transitionAnimation.sharedFlow(
- duration = 500.milliseconds,
- onStart = { startAlpha = viewState.alpha() },
- onStep = { MathUtils.lerp(startAlpha, 1f, it) },
- )
+ return transitionAnimation
+ .sharedFlow(
+ duration = 500.milliseconds,
+ onStart = { startAlpha = viewState.alpha() },
+ onStep = { MathUtils.lerp(startAlpha, 1f, it) },
+ )
+ .sample(powerInteractor.detailedWakefulness, ::Pair)
+ .transform { (alpha, wakefulness) ->
+ if (wakefulness.lastSleepReason != FOLD) {
+ emit(alpha)
+ }
+ }
+ }
+
+ val lockscreenAlphaOnFold: Flow<Float> =
+ transitionAnimationOnFold
+ .sharedFlow(
+ startTime = 600.milliseconds,
+ duration = 500.milliseconds,
+ onStep = { it },
+ )
+ .sample(powerInteractor.detailedWakefulness, ::Pair)
+ .transform { (alpha, wakefulness) ->
+ if (wakefulness.lastSleepReason == FOLD) {
+ emit(alpha)
+ }
+ }
+
+ val notificationAlphaOnFold: Flow<Float> =
+ transitionAnimationOnFold
+ .sharedFlow(
+ duration = 1100.milliseconds,
+ onStep = { 0f },
+ onFinish = { 1f },
+ )
+ .sample(powerInteractor.detailedWakefulness, ::Pair)
+ .transform { (alpha, wakefulness) ->
+ if (wakefulness.lastSleepReason == FOLD) {
+ emit(alpha)
+ }
+ }
+
+ /** x-translation from the side of the screen for fold animation */
+ fun enterFromSideTranslationX(translatePx: Int): Flow<StateToValue> {
+ return transitionAnimationOnFold
+ .sharedFlowWithState(
+ startTime = 600.milliseconds,
+ duration = 500.milliseconds,
+ onStep = { translatePx + it * -translatePx },
+ onFinish = { 0f },
+ interpolator = EMPHASIZED_DECELERATE,
+ )
+ .sample(powerInteractor.detailedWakefulness, ::Pair)
+ .transform { (stateToValue, wakefulness) ->
+ if (wakefulness.lastSleepReason == FOLD) {
+ emit(stateToValue)
+ }
+ }
}
override val deviceEntryParentViewAlpha: Flow<Float> =
diff --git a/packages/SystemUI/src/com/android/systemui/log/LogBufferFactory.kt b/packages/SystemUI/src/com/android/systemui/log/LogBufferFactory.kt
index e4465ac..6351d7d 100644
--- a/packages/SystemUI/src/com/android/systemui/log/LogBufferFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/LogBufferFactory.kt
@@ -19,10 +19,13 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dump.DumpManager
import com.android.systemui.log.LogBufferHelper.Companion.adjustMaxSize
+import com.android.systemui.log.echo.LogcatEchoTrackerAlways
import javax.inject.Inject
@SysUISingleton
-class LogBufferFactory @Inject constructor(
+class LogBufferFactory
+@Inject
+constructor(
private val dumpManager: DumpManager,
private val logcatEchoTracker: LogcatEchoTracker
) {
@@ -30,9 +33,11 @@
fun create(
name: String,
maxSize: Int,
- systrace: Boolean = true
+ systrace: Boolean = true,
+ alwaysLogToLogcat: Boolean = false,
): LogBuffer {
- val buffer = LogBuffer(name, adjustMaxSize(maxSize), logcatEchoTracker, systrace)
+ val echoTracker = if (alwaysLogToLogcat) LogcatEchoTrackerAlways else logcatEchoTracker
+ val buffer = LogBuffer(name, adjustMaxSize(maxSize), echoTracker, systrace)
dumpManager.registerBuffer(name, buffer)
return buffer
}
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
index 1e79f42..c7fde48 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
@@ -622,7 +622,8 @@
@SysUISingleton
@SceneFrameworkLog
public static LogBuffer provideSceneFrameworkLogBuffer(LogBufferFactory factory) {
- return factory.create("SceneFramework", 50);
+ return factory
+ .create("SceneFramework", 50, /* systrace */ true, /* alwaysLogToLogcat */ true);
}
/** Provides a {@link LogBuffer} for the bluetooth QS tile dialog. */
diff --git a/packages/SystemUI/src/com/android/systemui/log/echo/LogcatEchoTrackerAlways.kt b/packages/SystemUI/src/com/android/systemui/log/echo/LogcatEchoTrackerAlways.kt
new file mode 100644
index 0000000..ce096b3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/log/echo/LogcatEchoTrackerAlways.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.log.echo
+
+import com.android.systemui.log.LogcatEchoTracker
+import com.android.systemui.log.core.LogLevel
+
+/**
+ * The buffer and all of its tags will be logged to logcat at all times.
+ *
+ * This can be used for buffers that are important and should appear in bugreports in logcat
+ * directly.
+ */
+object LogcatEchoTrackerAlways : LogcatEchoTracker {
+ override fun isBufferLoggable(bufferName: String, level: LogLevel): Boolean = true
+
+ override fun isTagLoggable(tagName: String, level: LogLevel): Boolean = true
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java b/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java
index 1b3b473..988fe64 100644
--- a/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java
@@ -43,7 +43,7 @@
public class NotificationPlayer implements OnCompletionListener, OnErrorListener {
private static final int PLAY = 1;
private static final int STOP = 2;
- private static final boolean DEBUG = false;
+ private static final boolean DEBUG = true;
private static final class Command {
int code;
diff --git a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
index 3ab0420..e7c2a45 100644
--- a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
@@ -53,7 +53,7 @@
@SysUISingleton
public class RingtonePlayer implements CoreStartable {
private static final String TAG = "RingtonePlayer";
- private static final boolean LOGD = false;
+ private static final boolean LOGD = true;
private final Context mContext;
// TODO: support Uri switching under same IBinder
diff --git a/packages/SystemUI/src/com/android/systemui/navigation/data/repository/NavigationRepository.kt b/packages/SystemUI/src/com/android/systemui/navigation/data/repository/NavigationRepository.kt
new file mode 100644
index 0000000..4409e2c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/navigation/data/repository/NavigationRepository.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.navigation.data.repository
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.navigationbar.NavigationModeController
+import com.android.systemui.shared.system.QuickStepContract
+import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow
+import javax.inject.Inject
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+
+@SysUISingleton
+class NavigationRepository
+@Inject
+constructor(
+ private val controller: NavigationModeController,
+) {
+
+ /** Whether the current navigation bar mode is edge-to-edge. */
+ val isGesturalMode: Flow<Boolean> = conflatedCallbackFlow {
+ val listener =
+ NavigationModeController.ModeChangedListener { mode ->
+ trySend(QuickStepContract.isGesturalMode(mode))
+ }
+
+ val currentMode = controller.addListener(listener)
+ trySend(QuickStepContract.isGesturalMode(currentMode))
+
+ awaitClose { controller.removeListener(listener) }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/navigation/domain/interactor/NavigationInteractor.kt b/packages/SystemUI/src/com/android/systemui/navigation/domain/interactor/NavigationInteractor.kt
new file mode 100644
index 0000000..0f9c883
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/navigation/domain/interactor/NavigationInteractor.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.navigation.domain.interactor
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.navigation.data.repository.NavigationRepository
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+
+@SysUISingleton
+class NavigationInteractor
+@Inject
+constructor(
+ repository: NavigationRepository,
+) {
+
+ /** Whether the current navigation bar mode is edge-to-edge. */
+ val isGesturalMode: Flow<Boolean> = repository.isGesturalMode
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/CastAutoAddable.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/CastAutoAddable.kt
index b5bef9f..88f7169 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/CastAutoAddable.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/CastAutoAddable.kt
@@ -41,12 +41,7 @@
override fun ProducerScope<AutoAddSignal>.getCallback(): CastController.Callback {
return CastController.Callback {
- val isCasting =
- controller.castDevices.any {
- it.state == CastController.CastDevice.STATE_CONNECTED ||
- it.state == CastController.CastDevice.STATE_CONNECTING
- }
- if (isCasting) {
+ if (controller.castDevices.any { it.isCasting }) {
sendAdd()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
index b1b67cf..44c846b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
@@ -350,6 +350,10 @@
initialLongPressProperties?.width = width
finalLongPressProperties?.width = LONG_PRESS_EFFECT_WIDTH_SCALE * width
+
+ val deltaW = (LONG_PRESS_EFFECT_WIDTH_SCALE - 1f) * width
+ paddingForLaunch.left = -deltaW.toInt() / 2
+ paddingForLaunch.right = deltaW.toInt() / 2
}
private fun maybeUpdateLongPressEffectHeight(height: Float) {
@@ -357,6 +361,10 @@
initialLongPressProperties?.height = height
finalLongPressProperties?.height = LONG_PRESS_EFFECT_HEIGHT_SCALE * height
+
+ val deltaH = (LONG_PRESS_EFFECT_HEIGHT_SCALE - 1f) * height
+ paddingForLaunch.top = -deltaH.toInt() / 2
+ paddingForLaunch.bottom = deltaH.toInt() / 2
}
override fun onFocusChanged(gainFocus: Boolean, direction: Int, previouslyFocusedRect: Rect?) {
@@ -432,14 +440,16 @@
longPressEffect?.callback =
object : QSLongPressEffect.Callback {
- override fun onPrepareForLaunch() {
- prepareForLaunch()
- }
-
override fun onResetProperties() {
resetLongPressEffectProperties()
}
+ override fun onEffectFinishedReversing() {
+ // The long-press effect properties finished at the same starting point.
+ // This is the same as if the properties were reset
+ haveLongPressPropertiesBeenReset = true
+ }
+
override fun onStartAnimator() {
if (longPressEffectAnimator?.isRunning != true) {
longPressEffectAnimator =
@@ -1043,6 +1053,7 @@
getOverlayColorForState(Tile.STATE_ACTIVE),
Utils.getColorAttrDefaultColor(context, R.attr.onShadeActive),
)
+ prepareForLaunch()
}
private fun changeCornerRadius(radius: Float) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
index 169cdc1..8a72e8d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -60,7 +60,7 @@
import com.android.systemui.statusbar.pipeline.shared.data.model.DefaultConnectionModel;
import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepository;
import com.android.systemui.statusbar.policy.CastController;
-import com.android.systemui.statusbar.policy.CastController.CastDevice;
+import com.android.systemui.statusbar.policy.CastDevice;
import com.android.systemui.statusbar.policy.HotspotController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.DialogKt;
@@ -193,14 +193,13 @@
// case where multiple devices were active :-/.
private boolean willPopDialog() {
List<CastDevice> activeDevices = getActiveDevices();
- return activeDevices.isEmpty() || (activeDevices.get(0).tag instanceof RouteInfo);
+ return activeDevices.isEmpty() || (activeDevices.get(0).getTag() instanceof RouteInfo);
}
private List<CastDevice> getActiveDevices() {
ArrayList<CastDevice> activeDevices = new ArrayList<>();
for (CastDevice device : mController.getCastDevices()) {
- if (device.state == CastDevice.STATE_CONNECTED
- || device.state == CastDevice.STATE_CONNECTING) {
+ if (device.isCasting()) {
activeDevices.add(device);
}
}
@@ -276,7 +275,7 @@
// We always choose the first device that's in the CONNECTED state in the case where
// multiple devices are CONNECTED at the same time.
for (CastDevice device : devices) {
- if (device.state == CastDevice.STATE_CONNECTED) {
+ if (device.getState() == CastDevice.CastState.Connected) {
state.value = true;
state.secondaryLabel = getDeviceName(device);
state.stateDescription = state.stateDescription + ","
@@ -284,7 +283,7 @@
R.string.accessibility_cast_name, state.label);
connecting = false;
break;
- } else if (device.state == CastDevice.STATE_CONNECTING) {
+ } else if (device.getState() == CastDevice.CastState.Connecting) {
connecting = true;
}
}
@@ -315,7 +314,7 @@
}
private String getDeviceName(CastDevice device) {
- return device.name != null ? device.name
+ return device.getName() != null ? device.getName()
: mContext.getString(R.string.quick_settings_cast_device_default_name);
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
index 08175c3..4738dbd 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
@@ -41,6 +41,7 @@
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.stateIn
/**
@@ -102,7 +103,14 @@
* 2. When transitioning, which scenes are being transitioned between.
* 3. When transitioning, what the progress of the transition is.
*/
- val transitionState: StateFlow<ObservableTransitionState> = repository.transitionState
+ val transitionState: StateFlow<ObservableTransitionState> =
+ repository.transitionState
+ .onEach { logger.logSceneTransition(it) }
+ .stateIn(
+ scope = applicationScope,
+ started = SharingStarted.Eagerly,
+ initialValue = repository.transitionState.value,
+ )
/**
* The key of the scene that the UI is currently transitioning to or `null` if there is no
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/logger/SceneLogger.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/logger/SceneLogger.kt
index 9d6720b..cf1518e 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/logger/SceneLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/logger/SceneLogger.kt
@@ -16,6 +16,7 @@
package com.android.systemui.scene.shared.logger
+import com.android.compose.animation.scene.ObservableTransitionState
import com.android.compose.animation.scene.SceneKey
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.core.LogLevel
@@ -84,6 +85,30 @@
)
}
+ fun logSceneTransition(transitionState: ObservableTransitionState) {
+ when (transitionState) {
+ is ObservableTransitionState.Transition -> {
+ logBuffer.log(
+ tag = TAG,
+ level = LogLevel.INFO,
+ messageInitializer = {
+ str1 = transitionState.fromScene.toString()
+ str2 = transitionState.toScene.toString()
+ },
+ messagePrinter = { "Scene transition started: $str1 → $str2" },
+ )
+ }
+ is ObservableTransitionState.Idle -> {
+ logBuffer.log(
+ tag = TAG,
+ level = LogLevel.INFO,
+ messageInitializer = { str1 = transitionState.currentScene.toString() },
+ messagePrinter = { "Scene transition idle on: $str1" },
+ )
+ }
+ }
+ }
+
fun logVisibilityChange(
from: Boolean,
to: Boolean,
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/model/TransitionKeys.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/model/TransitionKeys.kt
index ef393e4..be95441 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/model/TransitionKeys.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/model/TransitionKeys.kt
@@ -31,6 +31,11 @@
val CollapseShadeInstantly = TransitionKey("CollapseShadeInstantly")
/**
+ * Reference to a scene transition that brings up the shade from the bottom instead of the top.
+ */
+ val OpenBottomShade = TransitionKey("OpenBottomShade")
+
+ /**
* Reference to a scene transition that can collapse the shade scene slightly faster than a
* normal collapse would.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/GoneSceneViewModel.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/GoneSceneViewModel.kt
index c34a6cd..ac91337 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/GoneSceneViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/GoneSceneViewModel.kt
@@ -16,6 +16,7 @@
package com.android.systemui.scene.ui.viewmodel
+import androidx.compose.ui.Alignment
import com.android.compose.animation.scene.Edge
import com.android.compose.animation.scene.Swipe
import com.android.compose.animation.scene.SwipeDirection
@@ -24,6 +25,7 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.scene.shared.model.SceneFamilies
+import com.android.systemui.scene.shared.model.TransitionKeys.OpenBottomShade
import com.android.systemui.scene.shared.model.TransitionKeys.ToSplitShade
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.shade.shared.model.ShadeMode
@@ -39,7 +41,7 @@
@Inject
constructor(
@Application private val applicationScope: CoroutineScope,
- shadeInteractor: ShadeInteractor,
+ private val shadeInteractor: ShadeInteractor,
) {
val destinationScenes: StateFlow<Map<UserAction, UserActionResult>> =
shadeInteractor.shadeMode
@@ -72,13 +74,17 @@
)
}
- put(
- Swipe(direction = SwipeDirection.Down),
- UserActionResult(
- SceneFamilies.NotifShade,
- ToSplitShade.takeIf { shadeMode is ShadeMode.Split }
+ if (shadeInteractor.shadeAlignment == Alignment.BottomEnd) {
+ put(Swipe.Up, UserActionResult(SceneFamilies.NotifShade, OpenBottomShade))
+ } else {
+ put(
+ Swipe.Down,
+ UserActionResult(
+ SceneFamilies.NotifShade,
+ ToSplitShade.takeIf { shadeMode is ShadeMode.Split }
+ )
)
- )
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotExecutor.kt b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotExecutor.kt
index 40d709d..3c3797b 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotExecutor.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotExecutor.kt
@@ -7,6 +7,7 @@
import android.view.WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE
import com.android.internal.logging.UiEventLogger
import com.android.internal.util.ScreenshotRequest
+import com.android.systemui.Flags.screenshotShelfUi2
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.display.data.repository.DisplayRepository
@@ -139,8 +140,8 @@
private suspend fun getDisplaysToScreenshot(requestType: Int): List<Display> {
val allDisplays = displays.first()
- return if (requestType == TAKE_SCREENSHOT_PROVIDED_IMAGE) {
- // If this is a provided image, let's show the UI on the default display only.
+ return if (requestType == TAKE_SCREENSHOT_PROVIDED_IMAGE || screenshotShelfUi2()) {
+ // If this is a provided image or using the shelf UI, just screenshot th default display
allDisplays.filter { it.displayId == Display.DEFAULT_DISPLAY }
} else {
allDisplays.filter { it.type in ALLOWED_DISPLAY_TYPES }
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 262befc..9624e0f 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -25,7 +25,6 @@
import static com.android.keyguard.KeyguardClockSwitch.LARGE;
import static com.android.keyguard.KeyguardClockSwitch.SMALL;
import static com.android.systemui.Flags.predictiveBackAnimateShade;
-import static com.android.systemui.Flags.shadeCollapseActivityLaunchFix;
import static com.android.systemui.Flags.smartspaceRelocateToBottom;
import static com.android.systemui.classifier.Classifier.BOUNCER_UNLOCK;
import static com.android.systemui.classifier.Classifier.GENERIC;
@@ -484,7 +483,9 @@
private float mBottomAreaShadeAlpha;
final ValueAnimator mBottomAreaShadeAlphaAnimator;
private final AnimatableProperty mPanelAlphaAnimator = AnimatableProperty.from("panelAlpha",
- NotificationPanelView::setPanelAlphaInternal,
+ (view, alpha) -> {
+ setAlphaInternal(alpha);
+ },
NotificationPanelView::getCurrentPanelAlpha,
R.id.panel_alpha_animator_tag, R.id.panel_alpha_animator_start_tag,
R.id.panel_alpha_animator_end_tag);
@@ -3075,6 +3076,11 @@
}
}
+ private void setAlphaInternal(float alpha) {
+ mKeyguardInteractor.setPanelAlpha(alpha / 255f);
+ mView.setPanelAlphaInternal(alpha);
+ }
+
@Override
public void setAlphaChangeAnimationEndAction(Runnable r) {
mPanelAlphaEndAction = r;
@@ -4118,11 +4124,7 @@
@Override
public boolean canBeCollapsed() {
- return !isFullyCollapsed() && !isTracking() && !isClosing()
- // Don't try to collapse if on keyguard, as the expansion fraction is 1 in this
- // case.
- && !(shadeCollapseActivityLaunchFix() && mExpandedFraction == 1f
- && mBarState == KEYGUARD);
+ return !isFullyCollapsed() && !isTracking() && !isClosing();
}
public void instantCollapse() {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt
index 004db16..ee8161c 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt
@@ -17,6 +17,7 @@
package com.android.systemui.shade
import android.view.MotionEvent
+import androidx.compose.ui.Alignment
import com.android.systemui.assist.AssistManager
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
@@ -24,6 +25,7 @@
import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.shared.model.SceneFamilies
import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.scene.shared.model.TransitionKeys.OpenBottomShade
import com.android.systemui.scene.shared.model.TransitionKeys.SlightlyFasterShadeCollapse
import com.android.systemui.shade.ShadeController.ShadeVisibilityListener
import com.android.systemui.shade.domain.interactor.ShadeInteractor
@@ -175,6 +177,7 @@
sceneInteractor.changeScene(
SceneFamilies.NotifShade,
"ShadeController.animateExpandShade",
+ OpenBottomShade.takeIf { shadeInteractor.shadeAlignment == Alignment.BottomEnd }
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeRepository.kt b/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeRepository.kt
index 7e1a310..4d43ad5 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeRepository.kt
@@ -15,7 +15,10 @@
*/
package com.android.systemui.shade.data.repository
+import android.content.Context
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.res.R
import com.android.systemui.shade.shared.flag.DualShade
import com.android.systemui.shade.shared.model.ShadeMode
import javax.inject.Inject
@@ -104,6 +107,9 @@
val shadeMode: StateFlow<ShadeMode>
+ /** Whether dual shade should be aligned to the bottom (true) or to the top (false). */
+ val isDualShadeAlignedToBottom: Boolean
+
/** True when QS is taking up the entire screen, i.e. fully expanded on a non-unfolded phone. */
@Deprecated("Use ShadeInteractor instead") val legacyQsFullscreen: StateFlow<Boolean>
@@ -174,7 +180,8 @@
/** Business logic for shade interactions */
@SysUISingleton
-class ShadeRepositoryImpl @Inject constructor() : ShadeRepository {
+class ShadeRepositoryImpl @Inject constructor(@Application applicationContext: Context) :
+ ShadeRepository {
private val _qsExpansion = MutableStateFlow(0f)
override val qsExpansion: StateFlow<Float> = _qsExpansion.asStateFlow()
@@ -223,6 +230,9 @@
val _shadeMode = MutableStateFlow(if (DualShade.isEnabled) ShadeMode.Dual else ShadeMode.Single)
override val shadeMode: StateFlow<ShadeMode> = _shadeMode.asStateFlow()
+ override val isDualShadeAlignedToBottom =
+ applicationContext.resources.getBoolean(R.bool.config_dualShadeAlignedToBottom)
+
override fun setShadeMode(shadeMode: ShadeMode) {
_shadeMode.value = shadeMode
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt
index 18407cc..ef0a842 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt
@@ -16,6 +16,7 @@
package com.android.systemui.shade.domain.interactor
+import com.android.systemui.shade.shared.model.ShadeAlignment
import com.android.systemui.shade.shared.model.ShadeMode
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
@@ -53,6 +54,9 @@
/** Emits true if the shade can be expanded from QQS to QS and false otherwise. */
val isExpandToQsEnabled: Flow<Boolean>
+
+ /** How to align the shade content. */
+ val shadeAlignment: ShadeAlignment
}
/** ShadeInteractor methods with implementations that differ between non-empty impls. */
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorEmptyImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorEmptyImpl.kt
index bb4baa3..6226d07 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorEmptyImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorEmptyImpl.kt
@@ -17,6 +17,7 @@
package com.android.systemui.shade.domain.interactor
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.shade.shared.model.ShadeAlignment
import com.android.systemui.shade.shared.model.ShadeMode
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
@@ -46,4 +47,5 @@
override val isShadeTouchable: Flow<Boolean> = inactiveFlowBoolean
override val isExpandToQsEnabled: Flow<Boolean> = inactiveFlowBoolean
override val shadeMode: StateFlow<ShadeMode> = MutableStateFlow(ShadeMode.Single)
+ override val shadeAlignment: ShadeAlignment = ShadeAlignment.Top
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt
index 4014512..55f019b 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt
@@ -24,6 +24,8 @@
import com.android.systemui.keyguard.shared.model.Edge
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.power.domain.interactor.PowerInteractor
+import com.android.systemui.shade.data.repository.ShadeRepository
+import com.android.systemui.shade.shared.model.ShadeAlignment
import com.android.systemui.statusbar.disableflags.data.repository.DisableFlagsRepository
import com.android.systemui.statusbar.phone.DozeParameters
import com.android.systemui.statusbar.policy.data.repository.UserSetupRepository
@@ -51,6 +53,7 @@
keyguardRepository: KeyguardRepository,
keyguardTransitionInteractor: KeyguardTransitionInteractor,
powerInteractor: PowerInteractor,
+ shadeRepository: ShadeRepository,
userSetupRepository: UserSetupRepository,
userSwitcherInteractor: UserSwitcherInteractor,
private val baseShadeInteractor: BaseShadeInteractor,
@@ -99,6 +102,13 @@
}
}
+ override val shadeAlignment: ShadeAlignment =
+ if (shadeRepository.isDualShadeAlignedToBottom) {
+ ShadeAlignment.Bottom
+ } else {
+ ShadeAlignment.Top
+ }
+
override val isExpandToQsEnabled: Flow<Boolean> =
combine(
disableFlagsRepository.disableFlags,
diff --git a/packages/SystemUI/src/com/android/systemui/shade/shared/model/ShadeAlignment.kt b/packages/SystemUI/src/com/android/systemui/shade/shared/model/ShadeAlignment.kt
new file mode 100644
index 0000000..06905379
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/shade/shared/model/ShadeAlignment.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.shade.shared.model
+
+/** Enumerates all supported alignments of the shade. */
+sealed interface ShadeAlignment {
+
+ /** Aligns the shade to the top. */
+ data object Top : ShadeAlignment
+
+ /** Aligns the shade to the bottom. */
+ data object Bottom : ShadeAlignment
+}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/OverlayShadeViewModel.kt b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/OverlayShadeViewModel.kt
index 0314091..b946129 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/OverlayShadeViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/OverlayShadeViewModel.kt
@@ -22,6 +22,7 @@
import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.shared.model.SceneFamilies
import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.shade.domain.interactor.ShadeInteractor
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.SharingStarted
@@ -38,6 +39,7 @@
constructor(
@Application applicationScope: CoroutineScope,
private val sceneInteractor: SceneInteractor,
+ shadeInteractor: ShadeInteractor
) {
/** The scene to show in the background when the overlay shade is open. */
val backgroundScene: StateFlow<SceneKey> =
@@ -49,6 +51,9 @@
initialValue = Scenes.Lockscreen,
)
+ /** Dictates whether the panel is aligned to the top or the bottom. */
+ val panelAlignment = shadeInteractor.shadeAlignment
+
/** Notifies that the user has clicked the semi-transparent background scrim. */
fun onScrimClicked() {
sceneInteractor.changeScene(
diff --git a/packages/SystemUI/src/com/android/systemui/smartspace/dagger/SmartspaceViewComponent.kt b/packages/SystemUI/src/com/android/systemui/smartspace/dagger/SmartspaceViewComponent.kt
index 6d951bf..abffd3c 100644
--- a/packages/SystemUI/src/com/android/systemui/smartspace/dagger/SmartspaceViewComponent.kt
+++ b/packages/SystemUI/src/com/android/systemui/smartspace/dagger/SmartspaceViewComponent.kt
@@ -18,8 +18,10 @@
import android.app.ActivityOptions
import android.app.PendingIntent
import android.content.Intent
+import android.os.Handler
import android.view.View
import android.view.ViewGroup
+import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.BcSmartspaceDataPlugin
import com.android.systemui.plugins.BcSmartspaceDataPlugin.UI_SURFACE_DREAM
@@ -51,19 +53,20 @@
@Provides
fun providesSmartspaceView(
- activityStarter: ActivityStarter,
- falsingManager: FalsingManager,
- parent: ViewGroup,
- @Named(PLUGIN) plugin: BcSmartspaceDataPlugin,
- viewWithCustomLayout: View?,
- onAttachListener: View.OnAttachStateChangeListener
- ):
- BcSmartspaceDataPlugin.SmartspaceView {
+ activityStarter: ActivityStarter,
+ falsingManager: FalsingManager,
+ parent: ViewGroup,
+ @Named(PLUGIN) plugin: BcSmartspaceDataPlugin,
+ viewWithCustomLayout: View?,
+ onAttachListener: View.OnAttachStateChangeListener,
+ @Background bgHandler: Handler,
+ ): BcSmartspaceDataPlugin.SmartspaceView {
val ssView = viewWithCustomLayout
as? BcSmartspaceDataPlugin.SmartspaceView
?: plugin.getView(parent)
// Currently, this is only used to provide SmartspaceView on Dream surface.
ssView.setUiSurface(UI_SURFACE_DREAM)
+ ssView.setBgHandler(bgHandler)
ssView.registerDataProvider(plugin)
ssView.setIntentStarter(object : BcSmartspaceDataPlugin.IntentStarter {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 9a82ecf..855798c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -40,6 +40,7 @@
import com.android.internal.policy.SystemBarUtils;
import com.android.systemui.animation.ShadeInterpolation;
import com.android.systemui.res.R;
+import com.android.systemui.scene.shared.flag.SceneContainerFlag;
import com.android.systemui.shade.transition.LargeScreenShadeInterpolator;
import com.android.systemui.statusbar.notification.ColorUpdateLogger;
import com.android.systemui.statusbar.notification.NotificationUtils;
@@ -93,6 +94,7 @@
private float mCornerAnimationDistance;
private float mActualWidth = -1;
private int mMaxIconsOnLockscreen;
+ private int mNotificationScrimPadding;
private boolean mCanModifyColorOfNotifications;
private boolean mCanInteract;
private NotificationStackScrollLayout mHostLayout;
@@ -136,6 +138,7 @@
mStatusBarHeight = SystemBarUtils.getStatusBarHeight(mContext);
mPaddingBetweenElements = res.getDimensionPixelSize(R.dimen.notification_divider_height);
mMaxIconsOnLockscreen = res.getInteger(R.integer.max_notif_icons_on_lockscreen);
+ mNotificationScrimPadding = res.getDimensionPixelSize(R.dimen.notification_side_paddings);
ViewGroup.LayoutParams layoutParams = getLayoutParams();
final int newShelfHeight = res.getDimensionPixelOffset(R.dimen.notification_shelf_height);
@@ -261,17 +264,33 @@
viewState.hasItemsInStableShelf = false;
}
- final float stackEnd = ambientState.getStackY() + ambientState.getStackHeight();
+ final float stackBottom = SceneContainerFlag.isEnabled()
+ ? getStackBottom(ambientState)
+ : ambientState.getStackY() + ambientState.getStackHeight();
+
if (viewState.hidden) {
// if the shelf is hidden, position it at the end of the stack (plus the clip
// padding), such that when it appears animated, it will smoothly move in from the
// bottom, without jump cutting any notifications
- viewState.setYTranslation(stackEnd + mPaddingBetweenElements);
+ viewState.setYTranslation(stackBottom + mPaddingBetweenElements);
} else {
- viewState.setYTranslation(stackEnd - viewState.height);
+ viewState.setYTranslation(stackBottom - viewState.height);
}
}
+ /**
+ * bottom-most position, where we can draw the stack
+ */
+ private float getStackBottom(AmbientState ambientState) {
+ if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return 0f;
+ float stackBottom = ambientState.getStackCutoff() - mNotificationScrimPadding;
+ if (ambientState.isExpansionChanging()) {
+ stackBottom = MathUtils.lerp(stackBottom * StackScrollAlgorithm.START_FRACTION,
+ stackBottom, ambientState.getExpansionFraction());
+ }
+ return stackBottom;
+ }
+
private int getSpeedBumpIndex() {
NotificationIconContainerRefactor.assertInLegacyMode();
return mHostLayout.getSpeedBumpIndex();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
index ee2c9cc..af8a89d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
@@ -109,6 +109,7 @@
@Main private val uiExecutor: Executor,
@Background private val bgExecutor: Executor,
@Main private val handler: Handler,
+ @Background private val bgHandler: Handler,
@Named(DATE_SMARTSPACE_DATA_PLUGIN)
optionalDatePlugin: Optional<BcSmartspaceDataPlugin>,
@Named(WEATHER_SMARTSPACE_DATA_PLUGIN)
@@ -412,6 +413,7 @@
val ssView = plugin.getView(parent)
configPlugin?.let { ssView.registerConfigProvider(it) }
+ ssView.setBgHandler(bgHandler)
ssView.setUiSurface(BcSmartspaceDataPlugin.UI_SURFACE_LOCK_SCREEN_AOD)
ssView.setTimeChangedDelegate(SmartspaceTimeChangedDelegate(keyguardUpdateMonitor))
ssView.registerDataProvider(plugin)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflater.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflater.kt
index 6fc82c9..463192c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflater.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflater.kt
@@ -244,7 +244,7 @@
return SingleIcon(null)
}
val userKey = user.getKeyOrName()
- var conversationIcon: Icon? = null
+ var conversationIcon: Icon? = shortcutIcon
var conversationText: CharSequence? = conversationTitle
val groups = groupMessages(messages, historicMessages)
@@ -253,10 +253,6 @@
if (!isGroupConversation) {
// Conversation is one-to-one, load the single icon
// Let's resolve the icon / text from the last sender
- if (shortcutIcon != null) {
- conversationIcon = shortcutIcon
- }
-
for (i in messages.lastIndex downTo 0) {
val message = messages[i]
val sender = message.senderPerson
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 5f4e832..456c321 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.dagger.SysUISingleton;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.res.R;
+import com.android.systemui.scene.shared.flag.SceneContainerFlag;
import com.android.systemui.shade.transition.LargeScreenShadeInterpolator;
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.StatusBarState;
@@ -63,6 +64,7 @@
* Used to read bouncer states.
*/
private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+ private float mStackCutoff;
private int mScrollY;
private float mOverScrollTopAmount;
private float mOverScrollBottomAmount;
@@ -346,6 +348,21 @@
return mZDistanceBetweenElements;
}
+ /**
+ * Y coordinate in view pixels above which the bottom of the notification stack / shelf / footer
+ * must be.
+ */
+ public float getStackCutoff() {
+ if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return 0f;
+ return mStackCutoff;
+ }
+
+ /** @see #getStackCutoff() */
+ public void setStackCutoff(float stackCutoff) {
+ if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return;
+ this.mStackCutoff = stackCutoff;
+ }
+
public int getScrollY() {
return mScrollY;
}
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 71a0b94..0e77ed4 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
@@ -837,8 +837,8 @@
y = (int) mScrollViewFields.getStackTop();
drawDebugInfo(canvas, y, Color.RED, /* label= */ "getStackTop() = " + y);
- y = (int) mScrollViewFields.getStackBottom();
- drawDebugInfo(canvas, y, Color.MAGENTA, /* label= */ "getStackBottom() = " + y);
+ y = (int) mAmbientState.getStackCutoff();
+ drawDebugInfo(canvas, y, Color.MAGENTA, /* label= */ "getStackCutoff() = " + y);
y = (int) mScrollViewFields.getHeadsUpTop();
drawDebugInfo(canvas, y, Color.GREEN, /* label= */ "getHeadsUpTop() = " + y);
@@ -1220,8 +1220,8 @@
}
@Override
- public void setStackBottom(float stackBottom) {
- mScrollViewFields.setStackBottom(stackBottom);
+ public void setStackCutoff(float stackCutoff) {
+ mAmbientState.setStackCutoff(stackCutoff);
}
@Override
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 6a3055f..d984685 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
@@ -68,7 +68,6 @@
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dump.DumpManager;
-import com.android.systemui.keyguard.MigrateClocksToBlueprint;
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository;
import com.android.systemui.keyguard.shared.model.KeyguardState;
import com.android.systemui.keyguard.shared.model.TransitionStep;
@@ -1320,7 +1319,10 @@
updateAlpha();
}
- void setMaxAlphaFromView(float alpha) {
+ /**
+ * Max alpha from the containing view. Used by brightness slider as an example.
+ */
+ public void setMaxAlphaFromView(float alpha) {
mMaxAlphaFromView = alpha;
updateAlpha();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ScrollViewFields.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ScrollViewFields.kt
index 6afcf37..2e86ad9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ScrollViewFields.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ScrollViewFields.kt
@@ -34,11 +34,6 @@
var scrimClippingShape: ShadeScrimShape? = null
/** Y coordinate in view pixels of the top of the notification stack */
var stackTop: Float = 0f
- /**
- * Y coordinate in view pixels above which the bottom of the notification stack / shelf / footer
- * must be.
- */
- var stackBottom: Float = 0f
/** Y coordinate in view pixels of the top of the HUN */
var headsUpTop: Float = 0f
/** Whether the notifications are scrolled all the way to the top (i.e. when freshly opened) */
@@ -70,9 +65,11 @@
/** send the [syntheticScroll] to the [syntheticScrollConsumer], if present. */
fun sendSyntheticScroll(syntheticScroll: Float) =
syntheticScrollConsumer?.accept(syntheticScroll)
+
/** send [isCurrentGestureOverscroll] to the [currentGestureOverscrollConsumer], if present. */
fun sendCurrentGestureOverscroll(isCurrentGestureOverscroll: Boolean) =
currentGestureOverscrollConsumer?.accept(isCurrentGestureOverscroll)
+
/** send the [headsUpHeight] to the [headsUpHeightConsumer], if present. */
fun sendHeadsUpHeight(headsUpHeight: Float) = headsUpHeightConsumer?.accept(headsUpHeight)
@@ -80,7 +77,6 @@
pw.printSection("StackViewStates") {
pw.println("scrimClippingShape", scrimClippingShape)
pw.println("stackTop", stackTop)
- pw.println("stackBottom", stackBottom)
pw.println("headsUpTop", headsUpTop)
pw.println("isScrolledToTop", isScrolledToTop)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/NotificationScrollView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/NotificationScrollView.kt
index eaaa9a1..762c507 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/NotificationScrollView.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/NotificationScrollView.kt
@@ -50,8 +50,11 @@
/** set the y position in px of the top of the stack in this view's coordinates */
fun setStackTop(stackTop: Float)
- /** set the y position in px of the bottom of the stack in this view's coordinates */
- fun setStackBottom(stackBottom: Float)
+ /**
+ * set the bottom-most acceptable y-position of the bottom of the notification stack/ shelf /
+ * footer.
+ */
+ fun setStackCutoff(stackBottom: Float)
/** set the y position in px of the top of the HUN in this view's coordinates */
fun setHeadsUpTop(headsUpTop: Float)
@@ -61,8 +64,10 @@
/** Set a consumer for synthetic scroll events */
fun setSyntheticScrollConsumer(consumer: Consumer<Float>?)
+
/** Set a consumer for current gesture overscroll events */
fun setCurrentGestureOverscrollConsumer(consumer: Consumer<Boolean>?)
+
/** Set a consumer for heads up height changed events */
fun setHeadsUpHeightConsumer(consumer: Consumer<Float>?)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt
index cf5366b..497ffca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt
@@ -154,6 +154,14 @@
}
}
+ if (!SceneContainerFlag.isEnabled) {
+ launch {
+ // For when the entire view should fade, such as with the brightness
+ // slider
+ viewModel.panelAlpha.collect { controller.setMaxAlphaFromView(it) }
+ }
+ }
+
if (communalHub()) {
launch {
viewModel.glanceableHubAlpha.collect {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt
index a21db12..ebb0d7d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt
@@ -90,8 +90,10 @@
1f
} else if (
shadeMode != ShadeMode.Split &&
- transitionState.fromScene in SceneFamilies.Home &&
- transitionState.toScene in quickSettingsScene
+ (transitionState.fromScene in SceneFamilies.Home &&
+ transitionState.toScene == quickSettingsScene) ||
+ (transitionState.fromScene == quickSettingsScene &&
+ transitionState.toScene in SceneFamilies.Home)
) {
// during QS expansion, increase fraction at same rate as scrim alpha,
// but start when scrim alpha is at EXPANSION_FOR_DELAYED_STACK_FADE_IN.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
index 1fc2821..8e58ffb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
@@ -21,6 +21,7 @@
import androidx.annotation.VisibleForTesting
import com.android.systemui.common.shared.model.NotificationContainerBounds
+import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dump.DumpManager
@@ -75,6 +76,7 @@
import com.android.systemui.util.kotlin.BooleanFlowOperators.anyOf
import com.android.systemui.util.kotlin.FlowDumperImpl
import com.android.systemui.util.kotlin.Utils.Companion.sample as sampleCombine
+import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -136,6 +138,7 @@
private val primaryBouncerToLockscreenTransitionViewModel:
PrimaryBouncerToLockscreenTransitionViewModel,
private val aodBurnInViewModel: AodBurnInViewModel,
+ private val communalSceneInteractor: CommunalSceneInteractor,
unfoldTransitionInteractor: UnfoldTransitionInteractor,
) : FlowDumperImpl(dumpManager) {
private val statesForConstrainedNotifications: Set<KeyguardState> =
@@ -470,6 +473,19 @@
}
.dumpWhileCollecting("isTransitioningToHiddenKeyguard")
+ val panelAlpha = keyguardInteractor.panelAlpha
+
+ private fun bouncerToGoneNotificationAlpha(viewState: ViewStateAccessor): Flow<Float> =
+ merge(
+ primaryBouncerToGoneTransitionViewModel.notificationAlpha,
+ alternateBouncerToGoneTransitionViewModel.notificationAlpha(viewState),
+ )
+ .sample(communalSceneInteractor.isCommunalVisible) { alpha, isCommunalVisible ->
+ // when glanceable hub is visible, hide notifications during the transition to GONE
+ if (isCommunalVisible) 0f else alpha
+ }
+ .dumpWhileCollecting("bouncerToGoneNotificationAlpha")
+
fun keyguardAlpha(viewState: ViewStateAccessor): Flow<Float> {
// All transition view models are mututally exclusive, and safe to merge
val alphaTransitions =
@@ -477,7 +493,7 @@
keyguardInteractor.dismissAlpha.dumpWhileCollecting(
"keyguardInteractor.dismissAlpha"
),
- alternateBouncerToGoneTransitionViewModel.notificationAlpha(viewState),
+ bouncerToGoneNotificationAlpha(viewState),
aodToGoneTransitionViewModel.notificationAlpha(viewState),
aodToLockscreenTransitionViewModel.notificationAlpha,
aodToOccludedTransitionViewModel.lockscreenAlpha(viewState),
@@ -495,8 +511,9 @@
occludedToAodTransitionViewModel.lockscreenAlpha,
occludedToGoneTransitionViewModel.notificationAlpha(viewState),
occludedToLockscreenTransitionViewModel.lockscreenAlpha,
- primaryBouncerToGoneTransitionViewModel.notificationAlpha,
primaryBouncerToLockscreenTransitionViewModel.lockscreenAlpha,
+ glanceableHubToLockscreenTransitionViewModel.keyguardAlpha,
+ lockscreenToGlanceableHubTransitionViewModel.keyguardAlpha,
)
return merge(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
index 2011332..91b5d0b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
@@ -39,7 +39,7 @@
import com.android.systemui.qs.pipeline.shared.QSPipelineFlagsRepository;
import com.android.systemui.res.R;
import com.android.systemui.statusbar.policy.CastController;
-import com.android.systemui.statusbar.policy.CastController.CastDevice;
+import com.android.systemui.statusbar.policy.CastDevice;
import com.android.systemui.statusbar.policy.DataSaverController;
import com.android.systemui.statusbar.policy.DataSaverController.Listener;
import com.android.systemui.statusbar.policy.DeviceControlsController;
@@ -430,8 +430,7 @@
boolean isCasting = false;
for (CastDevice device : mCastController.getCastDevices()) {
- if (device.state == CastDevice.STATE_CONNECTED
- || device.state == CastDevice.STATE_CONNECTING) {
+ if (device.isCasting()) {
isCasting = true;
break;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyActivityStarterInternalImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyActivityStarterInternalImpl.kt
index e400ab6..639560f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyActivityStarterInternalImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyActivityStarterInternalImpl.kt
@@ -247,9 +247,10 @@
val actuallyShowOverLockscreen =
showOverLockscreen &&
intent.isActivity &&
- (skipLockscreenChecks || activityIntentHelper.wouldPendingShowOverLockscreen(
- intent,
- lockScreenUserManager.currentUserId
+ (skipLockscreenChecks ||
+ activityIntentHelper.wouldPendingShowOverLockscreen(
+ intent,
+ lockScreenUserManager.currentUserId
))
val animate =
@@ -470,12 +471,16 @@
shadeControllerLazy.get().collapseShadeForActivityStart()
}
if (communalHub()) {
- communalSceneInteractor.snapToSceneForActivityStart(CommunalScenes.Blank)
+ communalSceneInteractor.changeSceneForActivityStartOnDismissKeyguard()
}
return deferred
}
override fun willRunAnimationOnKeyguard(): Boolean {
+ if (communalHub() && communalSceneInteractor.isIdleOnCommunal.value) {
+ // Override to false when launching activity over the hub that requires auth
+ return false
+ }
return willAnimateOnKeyguard
}
}
@@ -557,7 +562,7 @@
override fun onTransitionAnimationStart(isExpandingFullyAbove: Boolean) {
super.onTransitionAnimationStart(isExpandingFullyAbove)
if (communalHub()) {
- communalSceneInteractor.snapToSceneForActivityStart(
+ communalSceneInteractor.snapToScene(
CommunalScenes.Blank,
ActivityTransitionAnimator.TIMINGS.totalDuration
)
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 3784132..2371eed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -62,7 +62,7 @@
import com.android.systemui.statusbar.phone.ui.StatusBarIconController;
import com.android.systemui.statusbar.policy.BluetoothController;
import com.android.systemui.statusbar.policy.CastController;
-import com.android.systemui.statusbar.policy.CastController.CastDevice;
+import com.android.systemui.statusbar.policy.CastDevice;
import com.android.systemui.statusbar.policy.DataSaverController;
import com.android.systemui.statusbar.policy.DataSaverController.Listener;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
@@ -521,8 +521,7 @@
private void updateCast() {
boolean isCasting = false;
for (CastDevice device : mCast.getCastDevices()) {
- if (device.state == CastDevice.STATE_CONNECTING
- || device.state == CastDevice.STATE_CONNECTED) {
+ if (device.isCasting()) {
isCasting = true;
break;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastController.java
index abedd3220..a3dcc3b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastController.java
@@ -37,15 +37,4 @@
void onCastDevicesChanged();
}
- public static final class CastDevice {
- public static final int STATE_DISCONNECTED = 0;
- public static final int STATE_CONNECTING = 1;
- public static final int STATE_CONNECTED = 2;
-
- public String id;
- public String name;
- public String description;
- public int state = STATE_DISCONNECTED;
- public Object tag;
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java
index 64bdf60..45cb52a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java
@@ -19,15 +19,12 @@
import static android.media.MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY;
import android.content.Context;
-import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
import android.media.MediaRouter;
import android.media.MediaRouter.RouteInfo;
import android.media.projection.MediaProjectionInfo;
import android.media.projection.MediaProjectionManager;
import android.os.Handler;
-import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
@@ -37,8 +34,6 @@
import com.android.internal.annotations.GuardedBy;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dump.DumpManager;
-import com.android.systemui.res.R;
-import com.android.systemui.util.Utils;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -51,10 +46,11 @@
/** Platform implementation of the cast controller. **/
@SysUISingleton
public class CastControllerImpl implements CastController {
- private static final String TAG = "CastController";
+ public static final String TAG = "CastController";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private final Context mContext;
+ private final PackageManager mPackageManager;
@GuardedBy("mCallbacks")
private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
private final MediaRouter mMediaRouter;
@@ -68,8 +64,12 @@
private MediaProjectionInfo mProjection;
@Inject
- public CastControllerImpl(Context context, DumpManager dumpManager) {
+ public CastControllerImpl(
+ Context context,
+ PackageManager packageManager,
+ DumpManager dumpManager) {
mContext = context;
+ mPackageManager = packageManager;
mMediaRouter = (MediaRouter) context.getSystemService(Context.MEDIA_ROUTER_SERVICE);
mMediaRouter.setRouterGroupId(MediaRouter.MIRRORING_GROUP_ID);
mProjectionManager = (MediaProjectionManager)
@@ -156,36 +156,17 @@
final ArrayList<CastDevice> devices = new ArrayList<>();
synchronized(mRoutes) {
for (RouteInfo route : mRoutes.values()) {
- final CastDevice device = new CastDevice();
- device.id = route.getTag().toString();
- final CharSequence name = route.getName(mContext);
- device.name = name != null ? name.toString() : null;
- final CharSequence description = route.getDescription();
- device.description = description != null ? description.toString() : null;
-
- int statusCode = route.getStatusCode();
- if (statusCode == RouteInfo.STATUS_CONNECTING) {
- device.state = CastDevice.STATE_CONNECTING;
- } else if (route.isSelected() || statusCode == RouteInfo.STATUS_CONNECTED) {
- device.state = CastDevice.STATE_CONNECTED;
- } else {
- device.state = CastDevice.STATE_DISCONNECTED;
- }
-
- device.tag = route;
- devices.add(device);
+ devices.add(CastDevice.Companion.toCastDevice(route, mContext));
}
}
synchronized (mProjectionLock) {
if (mProjection != null) {
- final CastDevice device = new CastDevice();
- device.id = mProjection.getPackageName();
- device.name = getAppName(mProjection.getPackageName());
- device.description = mContext.getString(R.string.quick_settings_casting);
- device.state = CastDevice.STATE_CONNECTED;
- device.tag = mProjection;
- devices.add(device);
+ devices.add(
+ CastDevice.Companion.toCastDevice(
+ mProjection,
+ mContext,
+ mPackageManager));
}
}
@@ -194,18 +175,18 @@
@Override
public void startCasting(CastDevice device) {
- if (device == null || device.tag == null) return;
- final RouteInfo route = (RouteInfo) device.tag;
+ if (device == null || device.getTag() == null) return;
+ final RouteInfo route = (RouteInfo) device.getTag();
if (DEBUG) Log.d(TAG, "startCasting: " + routeToString(route));
mMediaRouter.selectRoute(ROUTE_TYPE_REMOTE_DISPLAY, route);
}
@Override
public void stopCasting(CastDevice device) {
- final boolean isProjection = device.tag instanceof MediaProjectionInfo;
+ final boolean isProjection = device.getTag() instanceof MediaProjectionInfo;
if (DEBUG) Log.d(TAG, "stopCasting isProjection=" + isProjection);
if (isProjection) {
- final MediaProjectionInfo projection = (MediaProjectionInfo) device.tag;
+ final MediaProjectionInfo projection = (MediaProjectionInfo) device.getTag();
if (Objects.equals(mProjectionManager.getActiveProjectionInfo(), projection)) {
mProjectionManager.stopActiveProjection();
} else {
@@ -219,7 +200,7 @@
@Override
public boolean hasConnectedCastDevice() {
return getCastDevices().stream().anyMatch(
- castDevice -> castDevice.state == CastDevice.STATE_CONNECTED);
+ castDevice -> castDevice.getState() == CastDevice.CastState.Connected);
}
private void setProjection(MediaProjectionInfo projection, boolean started) {
@@ -241,27 +222,6 @@
}
}
- private String getAppName(String packageName) {
- final PackageManager pm = mContext.getPackageManager();
- if (Utils.isHeadlessRemoteDisplayProvider(pm, packageName)) {
- return "";
- }
-
- try {
- final ApplicationInfo appInfo = pm.getApplicationInfo(packageName, 0);
- if (appInfo != null) {
- final CharSequence label = appInfo.loadLabel(pm);
- if (!TextUtils.isEmpty(label)) {
- return label.toString();
- }
- }
- Log.w(TAG, "No label found for package: " + packageName);
- } catch (NameNotFoundException e) {
- Log.w(TAG, "Error getting appName for package: " + packageName, e);
- }
- return packageName;
- }
-
private void updateRemoteDisplays() {
synchronized(mRoutes) {
mRoutes.clear();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastDevice.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastDevice.kt
new file mode 100644
index 0000000..5fc160b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastDevice.kt
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.statusbar.policy
+
+import android.content.Context
+import android.content.pm.PackageManager
+import android.media.MediaRouter
+import android.media.projection.MediaProjectionInfo
+import android.text.TextUtils
+import android.util.Log
+import com.android.systemui.res.R
+import com.android.systemui.util.Utils
+
+/** Represents a specific cast session. */
+data class CastDevice(
+ val id: String,
+ /** A human-readable name of what is receiving the cast (e.g. "Home Speaker", "Abc App"). */
+ val name: String?,
+ /** An optional description with more information about the cast. */
+ val description: String? = null,
+ val state: CastState,
+ val origin: CastOrigin,
+ /** Optional tag to use as a comparison value between cast sessions. */
+ val tag: Any? = null,
+) {
+ val isCasting = state == CastState.Connecting || state == CastState.Connected
+
+ companion object {
+ /** Creates a [CastDevice] based on the provided information from MediaRouter. */
+ fun MediaRouter.RouteInfo.toCastDevice(context: Context): CastDevice {
+ val state =
+ when {
+ statusCode == MediaRouter.RouteInfo.STATUS_CONNECTING -> CastState.Connecting
+ this.isSelected || statusCode == MediaRouter.RouteInfo.STATUS_CONNECTED ->
+ CastState.Connected
+ else -> CastState.Disconnected
+ }
+ return CastDevice(
+ id = this.tag.toString(),
+ name = this.getName(context)?.toString(),
+ description = this.description?.toString(),
+ state = state,
+ tag = this,
+ origin = CastOrigin.MediaRouter,
+ )
+ }
+
+ /** Creates a [CastDevice] based on the provided information from MediaProjection. */
+ fun MediaProjectionInfo.toCastDevice(
+ context: Context,
+ packageManager: PackageManager
+ ): CastDevice {
+ return CastDevice(
+ id = this.packageName,
+ name = getAppName(this.packageName, packageManager),
+ description = context.getString(R.string.quick_settings_casting),
+ state = CastState.Connected,
+ tag = this,
+ origin = CastOrigin.MediaProjection,
+ )
+ }
+
+ private fun getAppName(packageName: String, packageManager: PackageManager): String {
+ if (Utils.isHeadlessRemoteDisplayProvider(packageManager, packageName)) {
+ return ""
+ }
+ try {
+ val appInfo = packageManager.getApplicationInfo(packageName, 0)
+ val label = appInfo.loadLabel(packageManager)
+ if (!TextUtils.isEmpty(label)) {
+ return label.toString()
+ }
+ Log.w(CastControllerImpl.TAG, "No label found for package: $packageName")
+ } catch (e: PackageManager.NameNotFoundException) {
+ Log.w(CastControllerImpl.TAG, "Error getting appName for package: $packageName", e)
+ }
+ return packageName
+ }
+ }
+
+ enum class CastState {
+ Disconnected,
+ Connecting,
+ Connected,
+ }
+
+ enum class CastOrigin {
+ /** SysUI found out about this cast device from MediaRouter APIs. */
+ MediaRouter,
+ /** SysUI found out about this cast device from MediaProjection APIs. */
+ MediaProjection,
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java
index 50cf5cc5..9f12b18 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java
@@ -39,7 +39,6 @@
import androidx.test.filters.SmallTest;
import com.android.internal.logging.MetricsLogger;
-import com.android.keyguard.TestScopeProvider;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.animation.DialogTransitionAnimator;
import com.android.systemui.classifier.FalsingManagerFake;
@@ -54,14 +53,11 @@
import com.android.systemui.statusbar.connectivity.SignalCallback;
import com.android.systemui.statusbar.connectivity.WifiIndicators;
import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository;
-import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiInteractor;
import com.android.systemui.statusbar.policy.CastController;
-import com.android.systemui.statusbar.policy.CastController.CastDevice;
+import com.android.systemui.statusbar.policy.CastDevice;
import com.android.systemui.statusbar.policy.HotspotController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
-import kotlinx.coroutines.test.TestScope;
-
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -105,12 +101,10 @@
@Mock
private QsEventLogger mUiEventLogger;
- private WifiInteractor mWifiInteractor;
private final TileJavaAdapter mJavaAdapter = new TileJavaAdapter();
private final FakeConnectivityRepository mConnectivityRepository =
new FakeConnectivityRepository();
private final FakeFeatureFlags mFeatureFlags = new FakeFeatureFlags();
- private final TestScope mTestScope = TestScopeProvider.getTestScope();
private TestableLooper mTestableLooper;
private CastTile mCastTile;
@@ -172,8 +166,7 @@
@Test
public void testStateActive_wifiEnabledAndCasting() {
createAndStartTileOldImpl();
- CastController.CastDevice device = new CastController.CastDevice();
- device.state = CastController.CastDevice.STATE_CONNECTED;
+ CastDevice device = createConnectedCastDevice();
List<CastDevice> devices = new ArrayList<>();
devices.add(device);
when(mController.getCastDevices()).thenReturn(devices);
@@ -232,8 +225,7 @@
@Test
public void stateActive_wifiConnectedAndCasting_newPipeline() {
createAndStartTileNewImpl();
- CastController.CastDevice device = new CastController.CastDevice();
- device.state = CastDevice.STATE_CONNECTED;
+ CastDevice device = createConnectedCastDevice();
List<CastDevice> devices = new ArrayList<>();
devices.add(device);
when(mController.getCastDevices()).thenReturn(devices);
@@ -248,8 +240,7 @@
@Test
public void stateActive_ethernetConnectedAndCasting_newPipeline() {
createAndStartTileNewImpl();
- CastController.CastDevice device = new CastController.CastDevice();
- device.state = CastDevice.STATE_CONNECTED;
+ CastDevice device = createConnectedCastDevice();
List<CastDevice> devices = new ArrayList<>();
devices.add(device);
when(mController.getCastDevices()).thenReturn(devices);
@@ -286,8 +277,7 @@
@Test
public void testStateActive_hotspotEnabledAndConnectedAndCasting() {
createAndStartTileOldImpl();
- CastController.CastDevice device = new CastController.CastDevice();
- device.state = CastController.CastDevice.STATE_CONNECTED;
+ CastDevice device = createConnectedCastDevice();
List<CastDevice> devices = new ArrayList<>();
devices.add(device);
when(mController.getCastDevices()).thenReturn(devices);
@@ -309,9 +299,13 @@
@Test
public void testHandleClick_castDevicePresent() {
createAndStartTileOldImpl();
- CastController.CastDevice device = new CastController.CastDevice();
- device.state = CastDevice.STATE_CONNECTED;
- device.tag = mock(MediaRouter.RouteInfo.class);
+ CastDevice device = new CastDevice(
+ "id",
+ /* name= */ null,
+ /* description= */ null,
+ /* state= */ CastDevice.CastState.Connected,
+ /* origin= */ CastDevice.CastOrigin.MediaRouter,
+ /* tag= */ mock(MediaRouter.RouteInfo.class));
List<CastDevice> devices = new ArrayList<>();
devices.add(device);
when(mController.getCastDevices()).thenReturn(devices);
@@ -327,9 +321,13 @@
@Test
public void testHandleClick_projectionOnly() {
createAndStartTileOldImpl();
- CastController.CastDevice device = new CastController.CastDevice();
- device.state = CastDevice.STATE_CONNECTED;
- device.tag = mock(MediaProjectionInfo.class);
+ CastDevice device = new CastDevice(
+ "id",
+ /* name= */ null,
+ /* description= */ null,
+ /* state= */ CastDevice.CastState.Connected,
+ /* origin= */ CastDevice.CastOrigin.MediaProjection,
+ /* tag= */ mock(MediaProjectionInfo.class));
List<CastDevice> devices = new ArrayList<>();
devices.add(device);
when(mController.getCastDevices()).thenReturn(devices);
@@ -344,31 +342,40 @@
@Test
public void testUpdateState_projectionOnly() {
createAndStartTileOldImpl();
- CastController.CastDevice device = new CastController.CastDevice();
- device.state = CastDevice.STATE_CONNECTED;
- device.tag = mock(MediaProjectionInfo.class);
- device.name = "Test Projection Device";
+ CastDevice device = new CastDevice(
+ "id",
+ /* name= */ "Test Projection Device",
+ /* description= */ null,
+ /* state= */ CastDevice.CastState.Connected,
+ /* origin= */ CastDevice.CastOrigin.MediaProjection,
+ /* tag= */ mock(MediaProjectionInfo.class));
List<CastDevice> devices = new ArrayList<>();
devices.add(device);
when(mController.getCastDevices()).thenReturn(devices);
enableWifiAndProcessMessages();
assertEquals(Tile.STATE_ACTIVE, mCastTile.getState().state);
- assertTrue(mCastTile.getState().secondaryLabel.toString().startsWith(device.name));
+ assertTrue(mCastTile.getState().secondaryLabel.toString()
+ .startsWith("Test Projection Device"));
}
@Test
public void testUpdateState_castingAndProjection() {
createAndStartTileOldImpl();
- CastController.CastDevice casting = new CastController.CastDevice();
- casting.state = CastDevice.STATE_CONNECTED;
- casting.tag = mock(RouteInfo.class);
- casting.name = "Test Casting Device";
-
- CastController.CastDevice projection = new CastController.CastDevice();
- projection.state = CastDevice.STATE_CONNECTED;
- projection.tag = mock(MediaProjectionInfo.class);
- projection.name = "Test Projection Device";
+ CastDevice casting = new CastDevice(
+ "id1",
+ /* name= */ "Test Casting Device",
+ /* description= */ null,
+ /* state= */ CastDevice.CastState.Connected,
+ /* origin= */ CastDevice.CastOrigin.MediaRouter,
+ /* tag= */ mock(RouteInfo.class));
+ CastDevice projection = new CastDevice(
+ "id2",
+ /* name= */ "Test Projection Device",
+ /* description= */ null,
+ /* state= */ CastDevice.CastState.Connected,
+ /* origin= */ CastDevice.CastOrigin.MediaProjection,
+ /* tag= */ mock(MediaProjectionInfo.class));
List<CastDevice> devices = new ArrayList<>();
devices.add(casting);
@@ -379,22 +386,27 @@
// Note here that the tile should be active, and should choose casting over projection.
assertEquals(Tile.STATE_ACTIVE, mCastTile.getState().state);
- assertTrue(mCastTile.getState().secondaryLabel.toString().startsWith(casting.name));
+ assertTrue(mCastTile.getState().secondaryLabel.toString()
+ .startsWith("Test Casting Device"));
}
@Test
public void testUpdateState_connectedAndConnecting() {
createAndStartTileOldImpl();
- CastController.CastDevice connecting = new CastController.CastDevice();
- connecting.state = CastDevice.STATE_CONNECTING;
- connecting.tag = mock(RouteInfo.class);
- connecting.name = "Test Casting Device";
-
- CastController.CastDevice connected = new CastController.CastDevice();
- connected.state = CastDevice.STATE_CONNECTED;
- connected.tag = mock(RouteInfo.class);
- connected.name = "Test Casting Device";
-
+ CastDevice connecting = new CastDevice(
+ "id",
+ /* name= */ "Test Connecting Device",
+ /* description= */ null,
+ /* state= */ CastDevice.CastState.Connecting,
+ /* origin= */ CastDevice.CastOrigin.MediaRouter,
+ /* tag= */ mock(RouteInfo.class));
+ CastDevice connected = new CastDevice(
+ "id",
+ /* name= */ "Test Connected Device",
+ /* description= */ null,
+ /* state= */ CastDevice.CastState.Connected,
+ /* origin= */ CastDevice.CastOrigin.MediaRouter,
+ /* tag= */ mock(RouteInfo.class));
List<CastDevice> devices = new ArrayList<>();
devices.add(connecting);
devices.add(connected);
@@ -404,7 +416,8 @@
// Tile should be connected and always prefer the connected device.
assertEquals(Tile.STATE_ACTIVE, mCastTile.getState().state);
- assertTrue(mCastTile.getState().secondaryLabel.toString().startsWith(connected.name));
+ assertTrue(mCastTile.getState().secondaryLabel.toString()
+ .startsWith("Test Connected Device"));
}
@Test
@@ -427,8 +440,7 @@
@Test
public void testExpandView_casting_projection() {
createAndStartTileOldImpl();
- CastController.CastDevice device = new CastController.CastDevice();
- device.state = CastController.CastDevice.STATE_CONNECTED;
+ CastDevice device = createConnectedCastDevice();
List<CastDevice> devices = new ArrayList<>();
devices.add(device);
when(mController.getCastDevices()).thenReturn(devices);
@@ -441,9 +453,14 @@
@Test
public void testExpandView_connecting_projection() {
createAndStartTileOldImpl();
- CastController.CastDevice connecting = new CastController.CastDevice();
- connecting.state = CastDevice.STATE_CONNECTING;
- connecting.name = "Test Casting Device";
+ CastDevice connecting = new CastDevice(
+ "id",
+ /* name= */
+ "Test Projection Device",
+ /* description= */ null,
+ /* state= */ CastDevice.CastState.Connected,
+ /* origin= */ CastDevice.CastOrigin.MediaProjection,
+ /* tag= */ mock(MediaProjectionInfo.class));
List<CastDevice> devices = new ArrayList<>();
devices.add(connecting);
@@ -457,9 +474,14 @@
@Test
public void testExpandView_casting_mediaRoute() {
createAndStartTileOldImpl();
- CastController.CastDevice device = new CastController.CastDevice();
- device.state = CastDevice.STATE_CONNECTED;
- device.tag = mock(MediaRouter.RouteInfo.class);
+ CastDevice device = new CastDevice(
+ "id",
+ /* name= */ "Test Router Device",
+ /* description= */ null,
+ /* state= */ CastDevice.CastState.Connected,
+ /* origin= */ CastDevice.CastOrigin.MediaRouter,
+ /* tag= */ mock(RouteInfo.class));
+
List<CastDevice> devices = new ArrayList<>();
devices.add(device);
when(mController.getCastDevices()).thenReturn(devices);
@@ -472,11 +494,13 @@
@Test
public void testExpandView_connecting_mediaRoute() {
createAndStartTileOldImpl();
- CastController.CastDevice connecting = new CastController.CastDevice();
- connecting.state = CastDevice.STATE_CONNECTING;
- connecting.tag = mock(RouteInfo.class);
- connecting.name = "Test Casting Device";
-
+ CastDevice connecting = new CastDevice(
+ "id",
+ /* name= */ "Test Router Device",
+ /* description= */ null,
+ /* state= */ CastDevice.CastState.Connecting,
+ /* origin= */ CastDevice.CastOrigin.MediaRouter,
+ /* tag= */ mock(RouteInfo.class));
List<CastDevice> devices = new ArrayList<>();
devices.add(connecting);
when(mController.getCastDevices()).thenReturn(devices);
@@ -567,4 +591,14 @@
hotspotCallbackArgumentCaptor.capture());
mHotspotCallback = hotspotCallbackArgumentCaptor.getValue();
}
+
+ private CastDevice createConnectedCastDevice() {
+ return new CastDevice(
+ "id",
+ /* name= */ null,
+ /* description= */ null,
+ /* state= */ CastDevice.CastState.Connected,
+ /* origin= */ CastDevice.CastOrigin.MediaProjection,
+ /* tag= */ null);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotExecutorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotExecutorTest.kt
index bf7d909..dd6ba90 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotExecutorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotExecutorTest.kt
@@ -3,6 +3,8 @@
import android.content.ComponentName
import android.graphics.Bitmap
import android.net.Uri
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
import android.testing.AndroidTestingRunner
import android.view.Display
import android.view.Display.TYPE_EXTERNAL
@@ -15,6 +17,7 @@
import androidx.test.filters.SmallTest
import com.android.internal.logging.testing.UiEventLoggerFake
import com.android.internal.util.ScreenshotRequest
+import com.android.systemui.Flags
import com.android.systemui.SysuiTestCase
import com.android.systemui.display.data.repository.FakeDisplayRepository
import com.android.systemui.display.data.repository.display
@@ -77,6 +80,7 @@
}
@Test
+ @DisableFlags(Flags.FLAG_SCREENSHOT_SHELF_UI2)
fun executeScreenshots_severalDisplays_callsControllerForEachOne() =
testScope.runTest {
val internalDisplay = display(TYPE_INTERNAL, id = 0)
@@ -108,6 +112,32 @@
}
@Test
+ @EnableFlags(Flags.FLAG_SCREENSHOT_SHELF_UI2)
+ fun executeScreenshots_severalDisplaysShelfUi_justCallsOne() =
+ testScope.runTest {
+ val internalDisplay = display(TYPE_INTERNAL, id = 0)
+ val externalDisplay = display(TYPE_EXTERNAL, id = 1)
+ setDisplays(internalDisplay, externalDisplay)
+ val onSaved = { _: Uri? -> }
+ screenshotExecutor.executeScreenshots(createScreenshotRequest(), onSaved, callback)
+
+ verify(controllerFactory).create(eq(internalDisplay), any())
+
+ val capturer = ArgumentCaptor<ScreenshotData>()
+
+ verify(controller0).handleScreenshot(capturer.capture(), any(), any())
+ assertThat(capturer.value.displayId).isEqualTo(0)
+
+ assertThat(eventLogger.numLogs()).isEqualTo(1)
+ assertThat(eventLogger.get(0).eventId)
+ .isEqualTo(ScreenshotEvent.SCREENSHOT_REQUESTED_KEY_OTHER.id)
+ assertThat(eventLogger.get(0).packageName).isEqualTo(topComponent.packageName)
+
+ screenshotExecutor.onDestroy()
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_SCREENSHOT_SHELF_UI2)
fun executeScreenshots_providedImageType_callsOnlyDefaultDisplayController() =
testScope.runTest {
val internalDisplay = display(TYPE_INTERNAL, id = 0)
@@ -139,6 +169,7 @@
}
@Test
+ @DisableFlags(Flags.FLAG_SCREENSHOT_SHELF_UI2)
fun executeScreenshots_onlyVirtualDisplays_noInteractionsWithControllers() =
testScope.runTest {
setDisplays(display(TYPE_VIRTUAL, id = 0), display(TYPE_VIRTUAL, id = 1))
@@ -150,6 +181,7 @@
}
@Test
+ @DisableFlags(Flags.FLAG_SCREENSHOT_SHELF_UI2)
fun executeScreenshots_allowedTypes_allCaptured() =
testScope.runTest {
whenever(controllerFactory.create(any(), any())).thenReturn(controller0)
@@ -168,6 +200,7 @@
}
@Test
+ @DisableFlags(Flags.FLAG_SCREENSHOT_SHELF_UI2)
fun executeScreenshots_reportsOnFinishedOnlyWhenBothFinished() =
testScope.runTest {
setDisplays(display(TYPE_INTERNAL, id = 0), display(TYPE_EXTERNAL, id = 1))
@@ -193,6 +226,7 @@
}
@Test
+ @DisableFlags(Flags.FLAG_SCREENSHOT_SHELF_UI2)
fun executeScreenshots_oneFinishesOtherFails_reportFailsOnlyAtTheEnd() =
testScope.runTest {
setDisplays(display(TYPE_INTERNAL, id = 0), display(TYPE_EXTERNAL, id = 1))
@@ -220,6 +254,7 @@
}
@Test
+ @DisableFlags(Flags.FLAG_SCREENSHOT_SHELF_UI2)
fun executeScreenshots_allDisplaysFail_reportsFail() =
testScope.runTest {
setDisplays(display(TYPE_INTERNAL, id = 0), display(TYPE_EXTERNAL, id = 1))
@@ -247,6 +282,7 @@
}
@Test
+ @DisableFlags(Flags.FLAG_SCREENSHOT_SHELF_UI2)
fun onDestroy_propagatedToControllers() =
testScope.runTest {
setDisplays(display(TYPE_INTERNAL, id = 0), display(TYPE_EXTERNAL, id = 1))
@@ -259,6 +295,7 @@
}
@Test
+ @DisableFlags(Flags.FLAG_SCREENSHOT_SHELF_UI2)
fun removeWindows_propagatedToControllers() =
testScope.runTest {
setDisplays(display(TYPE_INTERNAL, id = 0), display(TYPE_EXTERNAL, id = 1))
@@ -273,6 +310,7 @@
}
@Test
+ @DisableFlags(Flags.FLAG_SCREENSHOT_SHELF_UI2)
fun onCloseSystemDialogsReceived_propagatedToControllers() =
testScope.runTest {
setDisplays(display(TYPE_INTERNAL, id = 0), display(TYPE_EXTERNAL, id = 1))
@@ -287,6 +325,7 @@
}
@Test
+ @DisableFlags(Flags.FLAG_SCREENSHOT_SHELF_UI2)
fun onCloseSystemDialogsReceived_someControllerHavePendingTransitions() =
testScope.runTest {
setDisplays(display(TYPE_INTERNAL, id = 0), display(TYPE_EXTERNAL, id = 1))
@@ -303,6 +342,7 @@
}
@Test
+ @DisableFlags(Flags.FLAG_SCREENSHOT_SHELF_UI2)
fun executeScreenshots_controllerCalledWithRequestProcessorReturnValue() =
testScope.runTest {
setDisplays(display(TYPE_INTERNAL, id = 0))
@@ -324,6 +364,7 @@
}
@Test
+ @DisableFlags(Flags.FLAG_SCREENSHOT_SHELF_UI2)
fun executeScreenshots_errorFromProcessor_logsScreenshotRequested() =
testScope.runTest {
setDisplays(display(TYPE_INTERNAL, id = 0), display(TYPE_EXTERNAL, id = 1))
@@ -341,6 +382,7 @@
}
@Test
+ @DisableFlags(Flags.FLAG_SCREENSHOT_SHELF_UI2)
fun executeScreenshots_errorFromProcessor_logsUiError() =
testScope.runTest {
setDisplays(display(TYPE_INTERNAL, id = 0), display(TYPE_EXTERNAL, id = 1))
@@ -358,6 +400,7 @@
}
@Test
+ @DisableFlags(Flags.FLAG_SCREENSHOT_SHELF_UI2)
fun executeScreenshots_errorFromProcessorOnDefaultDisplay_showsErrorNotification() =
testScope.runTest {
setDisplays(display(TYPE_INTERNAL, id = 0), display(TYPE_EXTERNAL, id = 1))
@@ -384,6 +427,7 @@
}
@Test
+ @DisableFlags(Flags.FLAG_SCREENSHOT_SHELF_UI2)
fun executeScreenshots_errorFromScreenshotController_reportsRequested() =
testScope.runTest {
setDisplays(display(TYPE_INTERNAL, id = 0), display(TYPE_EXTERNAL, id = 1))
@@ -404,6 +448,7 @@
}
@Test
+ @DisableFlags(Flags.FLAG_SCREENSHOT_SHELF_UI2)
fun executeScreenshots_errorFromScreenshotController_reportsError() =
testScope.runTest {
setDisplays(display(TYPE_INTERNAL, id = 0), display(TYPE_EXTERNAL, id = 1))
@@ -424,6 +469,7 @@
}
@Test
+ @DisableFlags(Flags.FLAG_SCREENSHOT_SHELF_UI2)
fun executeScreenshots_errorFromScreenshotController_showsErrorNotification() =
testScope.runTest {
setDisplays(display(TYPE_INTERNAL, id = 0), display(TYPE_EXTERNAL, id = 1))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
index c3cedf8..88b832d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
@@ -438,6 +438,7 @@
mFakeKeyguardRepository,
mKeyguardTransitionInteractor,
mPowerInteractor,
+ mShadeRepository,
new FakeUserSetupRepository(),
mock(UserSwitcherInteractor.class),
new ShadeInteractorLegacyImpl(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
index 6536405..13d44de 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
@@ -18,7 +18,6 @@
import static com.android.keyguard.KeyguardClockSwitch.LARGE;
import static com.android.keyguard.KeyguardClockSwitch.SMALL;
-import static com.android.systemui.Flags.FLAG_SHADE_COLLAPSE_ACTIVITY_LAUNCH_FIX;
import static com.android.systemui.shade.ShadeExpansionStateManagerKt.STATE_CLOSED;
import static com.android.systemui.shade.ShadeExpansionStateManagerKt.STATE_OPEN;
import static com.android.systemui.shade.ShadeExpansionStateManagerKt.STATE_OPENING;
@@ -48,7 +47,6 @@
import android.graphics.Point;
import android.os.PowerManager;
import android.platform.test.annotations.DisableFlags;
-import android.platform.test.annotations.EnableFlags;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.MotionEvent;
@@ -679,32 +677,6 @@
}
@Test
- @EnableFlags(FLAG_SHADE_COLLAPSE_ACTIVITY_LAUNCH_FIX)
- public void testCanBeCollapsed_expandedInKeyguard() {
- mStatusBarStateController.setState(KEYGUARD);
- mNotificationPanelViewController.setExpandedFraction(1f);
-
- assertThat(mNotificationPanelViewController.canBeCollapsed()).isFalse();
- }
-
- @Test
- @EnableFlags(FLAG_SHADE_COLLAPSE_ACTIVITY_LAUNCH_FIX)
- public void testCanBeCollapsed_expandedInShade() {
- mStatusBarStateController.setState(SHADE);
- mNotificationPanelViewController.setExpandedFraction(1f);
- assertThat(mNotificationPanelViewController.canBeCollapsed()).isTrue();
- }
-
- @Test
- @DisableFlags(FLAG_SHADE_COLLAPSE_ACTIVITY_LAUNCH_FIX)
- public void testCanBeCollapsed_expandedInKeyguard_flagDisabled() {
- mStatusBarStateController.setState(KEYGUARD);
- mNotificationPanelViewController.setExpandedFraction(1f);
-
- assertThat(mNotificationPanelViewController.canBeCollapsed()).isTrue();
- }
-
- @Test
@Ignore("b/341163515 - fails to clean up animators correctly")
public void testSwipeWhileLocked_notifiesKeyguardState() {
mStatusBarStateController.setState(KEYGUARD);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java
index 85541aa..06a883c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java
@@ -218,6 +218,7 @@
mKeyguardRepository,
keyguardTransitionInteractor,
powerInteractor,
+ mShadeRepository,
new FakeUserSetupRepository(),
mUserSwitcherInteractor,
new ShadeInteractorLegacyImpl(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt
index 750693c..97acc6e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt
@@ -40,7 +40,7 @@
@Before
fun setUp() {
- underTest = ShadeRepositoryImpl()
+ underTest = ShadeRepositoryImpl(getContext())
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
index 066ca1c..b944d72 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
@@ -136,6 +136,9 @@
private lateinit var handler: Handler
@Mock
+ private lateinit var bgHandler: Handler
+
+ @Mock
private lateinit var datePlugin: BcSmartspaceDataPlugin
@Mock
@@ -265,6 +268,7 @@
executor,
bgExecutor,
handler,
+ bgHandler,
Optional.of(datePlugin),
Optional.of(weatherPlugin),
Optional.of(plugin),
@@ -762,6 +766,7 @@
// THEN the existing session is reused and views are registered
verify(smartspaceManager, never()).createSmartspaceSession(any())
verify(smartspaceView2).setUiSurface(BcSmartspaceDataPlugin.UI_SURFACE_LOCK_SCREEN_AOD)
+ verify(smartspaceView2).setBgHandler(bgHandler)
verify(smartspaceView2).setTimeChangedDelegate(any())
verify(smartspaceView2).registerDataProvider(plugin)
verify(smartspaceView2).registerConfigProvider(configPlugin)
@@ -838,6 +843,7 @@
verify(dateSmartspaceView).setUiSurface(
BcSmartspaceDataPlugin.UI_SURFACE_LOCK_SCREEN_AOD)
verify(dateSmartspaceView).setTimeChangedDelegate(any())
+ verify(dateSmartspaceView).setBgHandler(bgHandler)
verify(dateSmartspaceView).registerDataProvider(datePlugin)
verify(dateSmartspaceView).setPrimaryTextColor(anyInt())
@@ -851,6 +857,7 @@
verify(weatherSmartspaceView).setUiSurface(
BcSmartspaceDataPlugin.UI_SURFACE_LOCK_SCREEN_AOD)
verify(weatherSmartspaceView).setTimeChangedDelegate(any())
+ verify(weatherSmartspaceView).setBgHandler(bgHandler)
verify(weatherSmartspaceView).registerDataProvider(weatherPlugin)
verify(weatherSmartspaceView).setPrimaryTextColor(anyInt())
@@ -863,6 +870,7 @@
verify(smartspaceView).setUiSurface(BcSmartspaceDataPlugin.UI_SURFACE_LOCK_SCREEN_AOD)
verify(smartspaceView).setTimeChangedDelegate(any())
+ verify(smartspaceView).setBgHandler(bgHandler)
verify(smartspaceView).registerDataProvider(plugin)
verify(smartspaceView).registerConfigProvider(configPlugin)
verify(smartspaceSession)
@@ -988,6 +996,9 @@
override fun setUiSurface(uiSurface: String) {
}
+ override fun setBgHandler(bgHandler: Handler?) {
+ }
+
override fun setTimeChangedDelegate(
delegate: BcSmartspaceDataPlugin.TimeChangedDelegate?
) {}
@@ -1020,6 +1031,9 @@
override fun setUiSurface(uiSurface: String) {
}
+ override fun setBgHandler(bgHandler: Handler?) {
+ }
+
override fun setTimeChangedDelegate(
delegate: BcSmartspaceDataPlugin.TimeChangedDelegate?
) {}
@@ -1048,6 +1062,9 @@
override fun setUiSurface(uiSurface: String) {
}
+ override fun setBgHandler(bgHandler: Handler?) {
+ }
+
override fun setTimeChangedDelegate(
delegate: BcSmartspaceDataPlugin.TimeChangedDelegate?
) {}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt
index 48e8f88..9b0fd96 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt
@@ -10,6 +10,8 @@
import com.android.keyguard.BouncerPanelExpansionCalculator.aboutToShowBouncerProgress
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.ShadeInterpolation
+import com.android.systemui.flags.DisableSceneContainer
+import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.res.R
@@ -30,8 +32,8 @@
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.mock
-import org.mockito.MockitoAnnotations
import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
/** Tests for {@link NotificationShelf}. */
@SmallTest
@@ -332,6 +334,144 @@
}
@Test
+ fun updateState_lastViewAlmostBelowShelf_completelyInShelf() {
+ val viewStart = 0f
+ val shelfClipStart = 0.001f
+
+ val expandableView = mock(ExpandableView::class.java)
+ whenever(expandableView.shelfIcon).thenReturn(mock(StatusBarIconView::class.java))
+ whenever(expandableView.translationY).thenReturn(viewStart)
+ whenever(expandableView.actualHeight).thenReturn(20)
+
+ whenever(expandableView.minHeight).thenReturn(20)
+ whenever(expandableView.shelfTransformationTarget).thenReturn(null) // use translationY
+ whenever(expandableView.isInShelf).thenReturn(true)
+
+ whenever(ambientState.isOnKeyguard).thenReturn(true)
+ whenever(ambientState.isExpansionChanging).thenReturn(false)
+ whenever(ambientState.isShadeExpanded).thenReturn(true)
+
+ val amountInShelf =
+ shelf.getAmountInShelf(
+ /* i= */ 0,
+ /* view= */ expandableView,
+ /* scrollingFast= */ false,
+ /* expandingAnimated= */ false,
+ /* isLastChild= */ true,
+ shelfClipStart
+ )
+ assertEquals(1f, amountInShelf)
+ }
+
+ @Test
+ @EnableSceneContainer
+ fun updateState_withViewInShelf_showShelf() {
+ // GIVEN a view is scrolled into the shelf
+ val stackCutoff = 200f
+ val scrimPadding =
+ context.resources.getDimensionPixelSize(R.dimen.notification_side_paddings)
+ val shelfTop = stackCutoff - scrimPadding - shelf.height
+ val stackScrollAlgorithmState = StackScrollAlgorithmState()
+ val viewInShelf = mock(ExpandableView::class.java)
+
+ whenever(ambientState.stackCutoff).thenReturn(stackCutoff)
+ whenever(ambientState.isShadeExpanded).thenReturn(true)
+ whenever(ambientState.lastVisibleBackgroundChild).thenReturn(viewInShelf)
+ whenever(viewInShelf.viewState).thenReturn(ExpandableViewState())
+ whenever(viewInShelf.shelfIcon).thenReturn(mock(StatusBarIconView::class.java))
+ whenever(viewInShelf.translationY).thenReturn(shelfTop)
+ whenever(viewInShelf.actualHeight).thenReturn(10)
+ whenever(viewInShelf.isInShelf).thenReturn(true)
+ whenever(viewInShelf.minHeight).thenReturn(10)
+ whenever(viewInShelf.shelfTransformationTarget).thenReturn(null) // use translationY
+ whenever(viewInShelf.isInShelf).thenReturn(true)
+
+ stackScrollAlgorithmState.visibleChildren.add(viewInShelf)
+ stackScrollAlgorithmState.firstViewInShelf = viewInShelf
+
+ // WHEN Shelf's ViewState is updated
+ shelf.updateState(stackScrollAlgorithmState, ambientState)
+
+ // THEN the shelf is visible, and positioned correctly
+ val shelfState = shelf.viewState as NotificationShelf.ShelfState
+ assertEquals(false, shelfState.hidden)
+ assertEquals(shelf.height, shelfState.height)
+ assertEquals(shelfTop, shelfState.yTranslation)
+ }
+
+ @Test
+ @EnableSceneContainer
+ fun updateState_withViewInShelfDuringExpansion_showShelf() {
+ // GIVEN a view is scrolled into the shelf
+ val stackCutoff = 200f
+ val scrimPadding =
+ context.resources.getDimensionPixelSize(R.dimen.notification_side_paddings)
+ val stackBottom = stackCutoff - scrimPadding
+ val shelfTop = stackBottom - shelf.height
+ val stackScrollAlgorithmState = StackScrollAlgorithmState()
+ val viewInShelf = mock(ExpandableView::class.java)
+
+ // AND a shade expansion is in progress
+ val shadeExpansionFraction = 0.5f
+
+ whenever(ambientState.stackCutoff).thenReturn(stackCutoff)
+ whenever(ambientState.isShadeExpanded).thenReturn(true)
+ whenever(ambientState.lastVisibleBackgroundChild).thenReturn(viewInShelf)
+ whenever(ambientState.isExpansionChanging).thenReturn(true)
+ whenever(ambientState.expansionFraction).thenReturn(shadeExpansionFraction)
+ whenever(viewInShelf.viewState).thenReturn(ExpandableViewState())
+ whenever(viewInShelf.shelfIcon).thenReturn(mock(StatusBarIconView::class.java))
+ whenever(viewInShelf.translationY).thenReturn(shelfTop)
+ whenever(viewInShelf.actualHeight).thenReturn(10)
+ whenever(viewInShelf.isInShelf).thenReturn(true)
+ whenever(viewInShelf.minHeight).thenReturn(10)
+ whenever(viewInShelf.shelfTransformationTarget).thenReturn(null) // use translationY
+ whenever(viewInShelf.isInShelf).thenReturn(true)
+
+ stackScrollAlgorithmState.visibleChildren.add(viewInShelf)
+ stackScrollAlgorithmState.firstViewInShelf = viewInShelf
+
+ // WHEN Shelf's ViewState is updated
+ shelf.updateState(stackScrollAlgorithmState, ambientState)
+
+ // THEN the shelf is visible
+ val shelfState = shelf.viewState as NotificationShelf.ShelfState
+ assertEquals(false, shelfState.hidden)
+ assertEquals(shelf.height, shelfState.height)
+ // AND its translation is scaled by the shade expansion
+ assertEquals((stackBottom * 0.75f) - shelf.height, shelfState.yTranslation)
+ }
+
+ @Test
+ @EnableSceneContainer
+ fun updateState_withNullLastVisibleBackgroundChild_hideShelf_withSceneContainer() {
+ // GIVEN
+ val stackCutoff = 200f
+ val scrimPadding =
+ context.resources.getDimensionPixelSize(R.dimen.notification_side_paddings)
+ val paddingBetweenElements =
+ context.resources.getDimensionPixelSize(R.dimen.notification_divider_height)
+ whenever(ambientState.stackCutoff).thenReturn(stackCutoff)
+ whenever(ambientState.isShadeExpanded).thenReturn(true)
+ val lastVisibleBackgroundChild = mock<ExpandableView>()
+ val expandableViewState = ExpandableViewState()
+ whenever(lastVisibleBackgroundChild.viewState).thenReturn(expandableViewState)
+ val stackScrollAlgorithmState = StackScrollAlgorithmState()
+ stackScrollAlgorithmState.firstViewInShelf = mock()
+
+ whenever(ambientState.lastVisibleBackgroundChild).thenReturn(null)
+
+ // WHEN
+ shelf.updateState(stackScrollAlgorithmState, ambientState)
+
+ // THEN
+ val shelfState = shelf.viewState as NotificationShelf.ShelfState
+ assertEquals(true, shelfState.hidden)
+ assertEquals(stackCutoff - scrimPadding + paddingBetweenElements, shelfState.yTranslation)
+ }
+
+ @Test
+ @DisableSceneContainer
fun updateState_withNullLastVisibleBackgroundChild_hideShelf() {
// GIVEN
whenever(ambientState.stackY).thenReturn(100f)
@@ -358,6 +498,35 @@
}
@Test
+ @EnableSceneContainer
+ fun updateState_withNullFirstViewInShelf_hideShelf_withSceneContainer() {
+ // GIVEN
+ val stackCutoff = 200f
+ val scrimPadding =
+ context.resources.getDimensionPixelSize(R.dimen.notification_side_paddings)
+ val paddingBetweenElements =
+ context.resources.getDimensionPixelSize(R.dimen.notification_divider_height)
+ whenever(ambientState.stackCutoff).thenReturn(stackCutoff)
+ whenever(ambientState.isShadeExpanded).thenReturn(true)
+ val lastVisibleBackgroundChild = mock<ExpandableView>()
+ val expandableViewState = ExpandableViewState()
+ whenever(lastVisibleBackgroundChild.viewState).thenReturn(expandableViewState)
+ whenever(ambientState.lastVisibleBackgroundChild).thenReturn(lastVisibleBackgroundChild)
+ val stackScrollAlgorithmState = StackScrollAlgorithmState()
+
+ stackScrollAlgorithmState.firstViewInShelf = null
+
+ // WHEN
+ shelf.updateState(stackScrollAlgorithmState, ambientState)
+
+ // THEN
+ val shelfState = shelf.viewState as NotificationShelf.ShelfState
+ assertEquals(true, shelfState.hidden)
+ assertEquals(stackCutoff - scrimPadding + paddingBetweenElements, shelfState.yTranslation)
+ }
+
+ @Test
+ @DisableSceneContainer
fun updateState_withNullFirstViewInShelf_hideShelf() {
// GIVEN
whenever(ambientState.stackY).thenReturn(100f)
@@ -384,6 +553,35 @@
}
@Test
+ @EnableSceneContainer
+ fun updateState_withCollapsedShade_hideShelf_withSceneContainer() {
+ // GIVEN
+ val stackCutoff = 200f
+ val scrimPadding =
+ context.resources.getDimensionPixelSize(R.dimen.notification_side_paddings)
+ val paddingBetweenElements =
+ context.resources.getDimensionPixelSize(R.dimen.notification_divider_height)
+ whenever(ambientState.stackCutoff).thenReturn(stackCutoff)
+ val lastVisibleBackgroundChild = mock<ExpandableView>()
+ val expandableViewState = ExpandableViewState()
+ whenever(lastVisibleBackgroundChild.viewState).thenReturn(expandableViewState)
+ whenever(ambientState.lastVisibleBackgroundChild).thenReturn(lastVisibleBackgroundChild)
+ val stackScrollAlgorithmState = StackScrollAlgorithmState()
+ stackScrollAlgorithmState.firstViewInShelf = mock()
+
+ whenever(ambientState.isShadeExpanded).thenReturn(false)
+
+ // WHEN
+ shelf.updateState(stackScrollAlgorithmState, ambientState)
+
+ // THEN
+ val shelfState = shelf.viewState as NotificationShelf.ShelfState
+ assertEquals(true, shelfState.hidden)
+ assertEquals(stackCutoff - scrimPadding + paddingBetweenElements, shelfState.yTranslation)
+ }
+
+ @Test
+ @DisableSceneContainer
fun updateState_withCollapsedShade_hideShelf() {
// GIVEN
whenever(ambientState.stackY).thenReturn(100f)
@@ -410,6 +608,49 @@
}
@Test
+ @EnableSceneContainer
+ fun updateState_withHiddenSectionBeforeShelf_hideShelf_withSceneContianer() {
+ // GIVEN
+ val stackCutoff = 200f
+ whenever(ambientState.stackCutoff).thenReturn(stackCutoff)
+ val scrimPadding =
+ context.resources.getDimensionPixelSize(R.dimen.notification_side_paddings)
+ val paddingBetweenElements =
+ context.resources.getDimensionPixelSize(R.dimen.notification_divider_height)
+ whenever(ambientState.isShadeExpanded).thenReturn(true)
+ val lastVisibleBackgroundChild = mock<ExpandableView>()
+ val expandableViewState = ExpandableViewState()
+ whenever(lastVisibleBackgroundChild.viewState).thenReturn(expandableViewState)
+ val stackScrollAlgorithmState = StackScrollAlgorithmState()
+ whenever(ambientState.lastVisibleBackgroundChild).thenReturn(lastVisibleBackgroundChild)
+
+ val ssaVisibleChild = mock<ExpandableView>()
+ val ssaVisibleChildState = ExpandableViewState()
+ ssaVisibleChildState.hidden = true
+ whenever(ssaVisibleChild.viewState).thenReturn(ssaVisibleChildState)
+
+ val ssaVisibleChild1 = mock<ExpandableView>()
+ val ssaVisibleChildState1 = ExpandableViewState()
+ ssaVisibleChildState1.hidden = true
+ whenever(ssaVisibleChild1.viewState).thenReturn(ssaVisibleChildState1)
+
+ stackScrollAlgorithmState.visibleChildren.add(ssaVisibleChild)
+ stackScrollAlgorithmState.visibleChildren.add(ssaVisibleChild1)
+ whenever(ambientState.isExpansionChanging).thenReturn(true)
+ whenever(ambientState.expansionFraction).thenReturn(1f)
+ stackScrollAlgorithmState.firstViewInShelf = ssaVisibleChild1
+
+ // WHEN
+ shelf.updateState(stackScrollAlgorithmState, ambientState)
+
+ // THEN
+ val shelfState = shelf.viewState as NotificationShelf.ShelfState
+ assertEquals(true, shelfState.hidden)
+ assertEquals(stackCutoff - scrimPadding + paddingBetweenElements, shelfState.yTranslation)
+ }
+
+ @Test
+ @DisableSceneContainer
fun updateState_withHiddenSectionBeforeShelf_hideShelf() {
// GIVEN
whenever(ambientState.stackY).thenReturn(100f)
@@ -461,12 +702,9 @@
expectedAlpha: Float
) {
val sbnMock: StatusBarNotification = mock()
- val mockEntry = mock<NotificationEntry>().apply {
- whenever(this.sbn).thenReturn(sbnMock)
- }
+ val mockEntry = mock<NotificationEntry>().apply { whenever(this.sbn).thenReturn(sbnMock) }
val row = ExpandableNotificationRow(mContext, null, mockEntry)
- whenever(ambientState.lastVisibleBackgroundChild)
- .thenReturn(row)
+ whenever(ambientState.lastVisibleBackgroundChild).thenReturn(row)
whenever(ambientState.isExpansionChanging).thenReturn(true)
whenever(ambientState.expansionFraction).thenReturn(expansionFraction)
whenever(hostLayoutController.speedBumpIndex).thenReturn(0)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
index f0bc655..665544d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
@@ -61,7 +61,7 @@
import com.android.systemui.qs.external.CustomTile;
import com.android.systemui.res.R;
import com.android.systemui.statusbar.policy.CastController;
-import com.android.systemui.statusbar.policy.CastController.CastDevice;
+import com.android.systemui.statusbar.policy.CastDevice;
import com.android.systemui.statusbar.policy.DataSaverController;
import com.android.systemui.statusbar.policy.DeviceControlsController;
import com.android.systemui.statusbar.policy.HotspotController;
@@ -422,9 +422,17 @@
}
private static List<CastDevice> buildFakeCastDevice(boolean isCasting) {
- CastDevice cd = new CastDevice();
- cd.state = isCasting ? CastDevice.STATE_CONNECTED : CastDevice.STATE_DISCONNECTED;
- return Collections.singletonList(cd);
+ CastDevice.CastState state = isCasting
+ ? CastDevice.CastState.Connected
+ : CastDevice.CastState.Disconnected;
+ return Collections.singletonList(
+ new CastDevice(
+ "id",
+ /* name= */ null,
+ /* description= */ null,
+ /* state= */ state,
+ /* origin= */ CastDevice.CastOrigin.MediaProjection,
+ /* tag= */ null));
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CastControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CastControllerImplTest.java
index 68c1b8d..6894e6c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CastControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CastControllerImplTest.java
@@ -9,6 +9,7 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.content.pm.PackageManager;
import android.media.MediaRouter;
import android.media.projection.MediaProjectionInfo;
import android.media.projection.MediaProjectionManager;
@@ -52,8 +53,12 @@
mContext.addMockSystemService(MediaRouter.class, mMediaRouter);
mContext.addMockSystemService(MediaProjectionManager.class, mMediaProjectionManager);
when(mMediaProjectionManager.getActiveProjectionInfo()).thenReturn(mProjection);
+ when(mProjection.getPackageName()).thenReturn("fake.package");
- mController = new CastControllerImpl(mContext, mock(DumpManager.class));
+ mController = new CastControllerImpl(
+ mContext,
+ mock(PackageManager.class),
+ mock(DumpManager.class));
}
@Test
@@ -148,16 +153,26 @@
@Test
public void hasConnectedCastDevice_connected() {
- CastController.CastDevice castDevice = new CastController.CastDevice();
- castDevice.state = CastController.CastDevice.STATE_CONNECTED;
+ CastDevice castDevice = new CastDevice(
+ "id",
+ /* name= */ null,
+ /* description= */ null,
+ /* state= */ CastDevice.CastState.Connected,
+ /* origin= */ CastDevice.CastOrigin.MediaProjection,
+ /* tag= */ null);
mController.startCasting(castDevice);
assertTrue(mController.hasConnectedCastDevice());
}
@Test
public void hasConnectedCastDevice_notConnected() {
- CastController.CastDevice castDevice = new CastController.CastDevice();
- castDevice.state = CastController.CastDevice.STATE_CONNECTING;
+ CastDevice castDevice = new CastDevice(
+ "id",
+ /* name= */ null,
+ /* description= */ null,
+ /* state= */ CastDevice.CastState.Connecting,
+ /* origin= */ CastDevice.CastOrigin.MediaProjection,
+ /* tag= */ null);
mController.startCasting(castDevice);
assertTrue(mController.hasConnectedCastDevice());
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CastDeviceTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CastDeviceTest.kt
new file mode 100644
index 0000000..03ad66c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CastDeviceTest.kt
@@ -0,0 +1,441 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy
+
+import android.Manifest
+import android.content.Intent
+import android.content.pm.ApplicationInfo
+import android.content.pm.PackageManager
+import android.content.pm.ResolveInfo
+import android.media.MediaRouter
+import android.media.projection.MediaProjectionInfo
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.policy.CastDevice.Companion.toCastDevice
+import com.google.common.truth.Truth.assertThat
+import kotlin.test.Test
+import org.mockito.ArgumentMatchers
+import org.mockito.Mockito.doAnswer
+import org.mockito.kotlin.any
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.whenever
+
+@SmallTest
+class CastDeviceTest : SysuiTestCase() {
+ private val mockAppInfo =
+ mock<ApplicationInfo>().apply { whenever(this.loadLabel(any())).thenReturn("") }
+
+ private val packageManager =
+ mock<PackageManager>().apply {
+ whenever(
+ this.checkPermission(
+ Manifest.permission.REMOTE_DISPLAY_PROVIDER,
+ HEADLESS_REMOTE_PACKAGE,
+ )
+ )
+ .thenReturn(PackageManager.PERMISSION_GRANTED)
+ whenever(
+ this.checkPermission(
+ Manifest.permission.REMOTE_DISPLAY_PROVIDER,
+ NORMAL_PACKAGE,
+ )
+ )
+ .thenReturn(PackageManager.PERMISSION_DENIED)
+
+ doAnswer {
+ // See Utils.isHeadlessRemoteDisplayProvider
+ if ((it.arguments[0] as Intent).`package` == HEADLESS_REMOTE_PACKAGE) {
+ emptyList()
+ } else {
+ listOf(mock<ResolveInfo>())
+ }
+ }
+ .whenever(this)
+ .queryIntentActivities(any(), ArgumentMatchers.anyInt())
+
+ whenever(this.getApplicationInfo(any<String>(), any<Int>())).thenReturn(mockAppInfo)
+ }
+
+ @Test
+ fun isCasting_disconnected_false() {
+ val device =
+ CastDevice(
+ id = "id",
+ name = "name",
+ state = CastDevice.CastState.Disconnected,
+ origin = CastDevice.CastOrigin.MediaRouter,
+ )
+
+ assertThat(device.isCasting).isFalse()
+ }
+
+ @Test
+ fun isCasting_connecting_true() {
+ val device =
+ CastDevice(
+ id = "id",
+ name = "name",
+ state = CastDevice.CastState.Connecting,
+ origin = CastDevice.CastOrigin.MediaRouter,
+ )
+
+ assertThat(device.isCasting).isTrue()
+ }
+
+ @Test
+ fun isCasting_connected_true() {
+ val device =
+ CastDevice(
+ id = "id",
+ name = "name",
+ state = CastDevice.CastState.Connected,
+ origin = CastDevice.CastOrigin.MediaRouter,
+ )
+
+ assertThat(device.isCasting).isTrue()
+ }
+
+ @Test
+ fun routeToCastDevice_statusNone_stateDisconnected() {
+ val route =
+ mockRouteInfo().apply {
+ whenever(this.statusCode).thenReturn(MediaRouter.RouteInfo.STATUS_NONE)
+ }
+
+ val device = route.toCastDevice(context)
+
+ assertThat(device.state).isEqualTo(CastDevice.CastState.Disconnected)
+ }
+
+ @Test
+ fun routeToCastDevice_statusNotAvailable_stateDisconnected() {
+ val route =
+ mockRouteInfo().apply {
+ whenever(this.statusCode).thenReturn(MediaRouter.RouteInfo.STATUS_NOT_AVAILABLE)
+ }
+
+ val device = route.toCastDevice(context)
+
+ assertThat(device.state).isEqualTo(CastDevice.CastState.Disconnected)
+ }
+
+ @Test
+ fun routeToCastDevice_statusScanning_stateDisconnected() {
+ val route =
+ mockRouteInfo().apply {
+ whenever(this.statusCode).thenReturn(MediaRouter.RouteInfo.STATUS_SCANNING)
+ }
+
+ val device = route.toCastDevice(context)
+
+ assertThat(device.state).isEqualTo(CastDevice.CastState.Disconnected)
+ }
+
+ @Test
+ fun routeToCastDevice_statusAvailable_isSelectedFalse_stateDisconnected() {
+ val route =
+ mockRouteInfo().apply {
+ whenever(this.statusCode).thenReturn(MediaRouter.RouteInfo.STATUS_AVAILABLE)
+ whenever(this.isSelected).thenReturn(false)
+ }
+
+ val device = route.toCastDevice(context)
+
+ assertThat(device.state).isEqualTo(CastDevice.CastState.Disconnected)
+ }
+
+ @Test
+ fun routeToCastDevice_statusAvailable_isSelectedTrue_stateConnected() {
+ val route =
+ mockRouteInfo().apply {
+ whenever(this.statusCode).thenReturn(MediaRouter.RouteInfo.STATUS_AVAILABLE)
+ whenever(this.isSelected).thenReturn(true)
+ }
+
+ val device = route.toCastDevice(context)
+
+ assertThat(device.state).isEqualTo(CastDevice.CastState.Connected)
+ }
+
+ @Test
+ fun routeToCastDevice_statusInUse_isSelectedFalse_stateDisconnected() {
+ val route =
+ mockRouteInfo().apply {
+ whenever(this.statusCode).thenReturn(MediaRouter.RouteInfo.STATUS_IN_USE)
+ whenever(this.isSelected).thenReturn(false)
+ }
+
+ val device = route.toCastDevice(context)
+
+ assertThat(device.state).isEqualTo(CastDevice.CastState.Disconnected)
+ }
+
+ @Test
+ fun routeToCastDevice_statusInUse_isSelectedTrue_stateConnected() {
+ val route =
+ mockRouteInfo().apply {
+ whenever(this.statusCode).thenReturn(MediaRouter.RouteInfo.STATUS_IN_USE)
+ whenever(this.isSelected).thenReturn(true)
+ }
+
+ val device = route.toCastDevice(context)
+
+ assertThat(device.state).isEqualTo(CastDevice.CastState.Connected)
+ }
+
+ @Test
+ fun routeToCastDevice_statusConnecting_isSelectedFalse_stateConnecting() {
+ val route =
+ mockRouteInfo().apply {
+ whenever(this.statusCode).thenReturn(MediaRouter.RouteInfo.STATUS_CONNECTING)
+ whenever(this.isSelected).thenReturn(false)
+ }
+
+ val device = route.toCastDevice(context)
+
+ assertThat(device.state).isEqualTo(CastDevice.CastState.Connecting)
+ }
+
+ @Test
+ fun routeToCastDevice_statusConnecting_isSelectedTrue_stateConnecting() {
+ val route =
+ mockRouteInfo().apply {
+ whenever(this.statusCode).thenReturn(MediaRouter.RouteInfo.STATUS_CONNECTING)
+ whenever(this.isSelected).thenReturn(true)
+ }
+
+ val device = route.toCastDevice(context)
+
+ assertThat(device.state).isEqualTo(CastDevice.CastState.Connecting)
+ }
+
+ @Test
+ fun routeToCastDevice_statusConnected_isSelectedFalse_stateConnected() {
+ val route =
+ mockRouteInfo().apply {
+ whenever(this.statusCode).thenReturn(MediaRouter.RouteInfo.STATUS_CONNECTED)
+ whenever(this.isSelected).thenReturn(false)
+ }
+
+ val device = route.toCastDevice(context)
+
+ assertThat(device.state).isEqualTo(CastDevice.CastState.Connected)
+ }
+
+ @Test
+ fun routeToCastDevice_statusConnected_isSelectedTrue_stateConnected() {
+ val route =
+ mockRouteInfo().apply {
+ whenever(this.statusCode).thenReturn(MediaRouter.RouteInfo.STATUS_CONNECTED)
+ whenever(this.isSelected).thenReturn(true)
+ }
+
+ val device = route.toCastDevice(context)
+
+ assertThat(device.state).isEqualTo(CastDevice.CastState.Connected)
+ }
+
+ @Test
+ fun routeToCastDevice_tagIsStringType_idMatchesTag() {
+ val route = mock<MediaRouter.RouteInfo>().apply { whenever(this.tag).thenReturn("FakeTag") }
+
+ val device = route.toCastDevice(context)
+
+ assertThat(device.id).isEqualTo("FakeTag")
+ }
+
+ @Test
+ fun routeToCastDevice_tagIsOtherType_idMatchesTag() {
+ val tag = listOf("tag1", "tag2")
+ val route = mock<MediaRouter.RouteInfo>().apply { whenever(this.tag).thenReturn(tag) }
+
+ val device = route.toCastDevice(context)
+
+ assertThat(device.id).isEqualTo(tag.toString())
+ }
+
+ @Test
+ fun routeToCastDevice_nameMatchesName() {
+ val route = mockRouteInfo().apply { whenever(this.getName(context)).thenReturn("FakeName") }
+
+ val device = route.toCastDevice(context)
+
+ assertThat(device.name).isEqualTo("FakeName")
+ }
+
+ @Test
+ fun routeToCastDevice_descriptionMatchesDescription() {
+ val route =
+ mockRouteInfo().apply { whenever(this.description).thenReturn("FakeDescription") }
+
+ val device = route.toCastDevice(context)
+
+ assertThat(device.description).isEqualTo("FakeDescription")
+ }
+
+ @Test
+ fun routeToCastDevice_tagIsRoute() {
+ val route = mockRouteInfo()
+
+ val device = route.toCastDevice(context)
+
+ assertThat(device.tag).isEqualTo(route)
+ }
+
+ @Test
+ fun routeToCastDevice_originIsMediaRouter() {
+ val route = mockRouteInfo()
+
+ val device = route.toCastDevice(context)
+
+ assertThat(device.origin).isEqualTo(CastDevice.CastOrigin.MediaRouter)
+ }
+
+ @Test
+ fun routeToCastDevice_nullValues_ok() {
+ val device = mockRouteInfo().toCastDevice(context)
+
+ assertThat(device.name).isNull()
+ assertThat(device.description).isNull()
+ }
+
+ @Test
+ fun projectionToCastDevice_idMatchesPackage() {
+ val projection =
+ mock<MediaProjectionInfo>().apply {
+ whenever(this.packageName).thenReturn("fake.package")
+ }
+
+ val device = projection.toCastDevice(context, packageManager)
+
+ assertThat(device.id).isEqualTo("fake.package")
+ }
+
+ @Test
+ fun projectionToCastDevice_name_packageIsHeadlessRemote_isEmpty() {
+ val projection =
+ mock<MediaProjectionInfo>().apply {
+ whenever(this.packageName).thenReturn(HEADLESS_REMOTE_PACKAGE)
+ }
+
+ val device = projection.toCastDevice(context, packageManager)
+
+ assertThat(device.name).isEmpty()
+ }
+
+ @Test
+ fun projectionToCastDevice_name_packageMissingFromPackageManager_isPackageName() {
+ val projection =
+ mock<MediaProjectionInfo>().apply {
+ whenever(this.packageName).thenReturn(NORMAL_PACKAGE)
+ }
+
+ whenever(packageManager.getApplicationInfo(eq(NORMAL_PACKAGE), any<Int>()))
+ .thenThrow(PackageManager.NameNotFoundException())
+
+ val device = projection.toCastDevice(context, packageManager)
+
+ assertThat(device.name).isEqualTo(NORMAL_PACKAGE)
+ }
+
+ @Test
+ fun projectionToCastDevice_name_nameFromPackageManagerEmpty_isPackageName() {
+ val projection =
+ mock<MediaProjectionInfo>().apply {
+ whenever(this.packageName).thenReturn(NORMAL_PACKAGE)
+ }
+
+ val appInfo = mock<ApplicationInfo>()
+ whenever(appInfo.loadLabel(packageManager)).thenReturn("")
+ whenever(packageManager.getApplicationInfo(eq(NORMAL_PACKAGE), any<Int>()))
+ .thenReturn(appInfo)
+
+ val device = projection.toCastDevice(context, packageManager)
+
+ assertThat(device.name).isEqualTo(NORMAL_PACKAGE)
+ }
+
+ @Test
+ fun projectionToCastDevice_name_packageManagerHasName_isName() {
+ val projection =
+ mock<MediaProjectionInfo>().apply {
+ whenever(this.packageName).thenReturn(NORMAL_PACKAGE)
+ }
+
+ val appInfo = mock<ApplicationInfo>()
+ whenever(appInfo.loadLabel(packageManager)).thenReturn("Valid App Name")
+ whenever(packageManager.getApplicationInfo(eq(NORMAL_PACKAGE), any<Int>()))
+ .thenReturn(appInfo)
+
+ val device = projection.toCastDevice(context, packageManager)
+
+ assertThat(device.name).isEqualTo("Valid App Name")
+ }
+
+ @Test
+ fun projectionToCastDevice_descriptionIsCasting() {
+ val projection = mockProjectionInfo()
+
+ val device = projection.toCastDevice(context, packageManager)
+
+ assertThat(device.description).isEqualTo(context.getString(R.string.quick_settings_casting))
+ }
+
+ @Test
+ fun projectionToCastDevice_stateIsConnected() {
+ val projection = mockProjectionInfo()
+
+ val device = projection.toCastDevice(context, packageManager)
+
+ assertThat(device.state).isEqualTo(CastDevice.CastState.Connected)
+ }
+
+ @Test
+ fun projectionToCastDevice_tagIsProjection() {
+ val projection = mockProjectionInfo()
+
+ val device = projection.toCastDevice(context, packageManager)
+
+ assertThat(device.tag).isEqualTo(projection)
+ }
+
+ @Test
+ fun projectionToCastDevice_originIsMediaProjection() {
+ val projection = mockProjectionInfo()
+
+ val device = projection.toCastDevice(context, packageManager)
+
+ assertThat(device.origin).isEqualTo(CastDevice.CastOrigin.MediaProjection)
+ }
+
+ private fun mockRouteInfo(): MediaRouter.RouteInfo {
+ return mock<MediaRouter.RouteInfo>().apply { whenever(this.tag).thenReturn(Any()) }
+ }
+
+ private fun mockProjectionInfo(): MediaProjectionInfo {
+ return mock<MediaProjectionInfo>().apply {
+ whenever(this.packageName).thenReturn("fake.package")
+ }
+ }
+
+ private companion object {
+ const val HEADLESS_REMOTE_PACKAGE = "headless.remote.package"
+ const val NORMAL_PACKAGE = "normal.package"
+ }
+}
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 4654a4d..6efb7d8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
@@ -35,6 +35,7 @@
import static org.mockito.ArgumentMatchers.any;
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.reset;
import static org.mockito.Mockito.times;
@@ -783,8 +784,8 @@
mDialog.show(SHOW_REASON_UNKNOWN);
mTestableLooper.processAllMessages();
- verify(mVolumeDialogInteractor).onDialogShown();
- verify(mVolumeDialogInteractor).onDialogDismissed(); // dismiss by timeout
+ verify(mVolumeDialogInteractor, atLeastOnce()).onDialogShown();
+ verify(mVolumeDialogInteractor, atLeastOnce()).onDialogDismissed(); // dismiss by timeout
}
/**
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceconfig/data/repository/DeviceConfigRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceconfig/data/repository/DeviceConfigRepositoryKosmos.kt
new file mode 100644
index 0000000..e4efadbd
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceconfig/data/repository/DeviceConfigRepositoryKosmos.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.deviceconfig.data.repository
+
+import com.android.systemui.concurrency.fakeExecutor
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.util.deviceConfigProxy
+
+val Kosmos.deviceConfigRepository by Fixture {
+ DeviceConfigRepository(
+ backgroundExecutor = fakeExecutor,
+ backgroundDispatcher = testDispatcher,
+ dataSource = deviceConfigProxy,
+ )
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceconfig/domain/interactor/DeviceConfigInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceconfig/domain/interactor/DeviceConfigInteractorKosmos.kt
new file mode 100644
index 0000000..d538497
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceconfig/domain/interactor/DeviceConfigInteractorKosmos.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.deviceconfig.domain.interactor
+
+import com.android.systemui.deviceconfig.data.repository.deviceConfigRepository
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+
+val Kosmos.deviceConfigInteractor by Fixture {
+ DeviceConfigInteractor(
+ repository = deviceConfigRepository,
+ )
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
index 2d100f0..dca531a 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
@@ -119,6 +119,8 @@
private val _keyguardAlpha = MutableStateFlow(1f)
override val keyguardAlpha: StateFlow<Float> = _keyguardAlpha
+ override val panelAlpha: MutableStateFlow<Float> = MutableStateFlow(1f)
+
override val lastRootViewTapPosition: MutableStateFlow<Point?> = MutableStateFlow(null)
override val ambientIndicationVisible: MutableStateFlow<Boolean> = MutableStateFlow(false)
@@ -259,6 +261,10 @@
_keyguardAlpha.value = alpha
}
+ override fun setPanelAlpha(alpha: Float) {
+ panelAlpha.value = alpha
+ }
+
fun setIsEncryptedOrLockdown(value: Boolean) {
_isEncryptedOrLockdown.value = value
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelKosmos.kt
index 6f168d4..6cf668c 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelKosmos.kt
@@ -33,6 +33,7 @@
keyguardInteractor = keyguardInteractor,
keyguardTransitionInteractor = keyguardTransitionInteractor,
goneToAodTransitionViewModel = goneToAodTransitionViewModel,
+ lockscreenToAodTransitionViewModel = lockscreenToAodTransitionViewModel,
aodToLockscreenTransitionViewModel = aodToLockscreenTransitionViewModel,
occludedToLockscreenTransitionViewModel = occludedToLockscreenTransitionViewModel,
keyguardClockViewModel = keyguardClockViewModel,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModelKosmos.kt
index 19e4241..8549a30 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModelKosmos.kt
@@ -22,11 +22,13 @@
import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.power.domain.interactor.powerInteractor
import kotlinx.coroutines.ExperimentalCoroutinesApi
var Kosmos.goneToAodTransitionViewModel by Fixture {
GoneToAodTransitionViewModel(
deviceEntryUdfpsInteractor = deviceEntryUdfpsInteractor,
+ powerInteractor = powerInteractor,
animationFlow = keyguardTransitionAnimationFlow,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModelKosmos.kt
index 07b4cd4..f45e33b 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModelKosmos.kt
@@ -22,11 +22,13 @@
import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.power.domain.interactor.powerInteractor
import kotlinx.coroutines.ExperimentalCoroutinesApi
-val Kosmos.lockscreenToAodTransitionViewModel by Fixture {
+var Kosmos.lockscreenToAodTransitionViewModel by Fixture {
LockscreenToAodTransitionViewModel(
deviceEntryUdfpsInteractor = deviceEntryUdfpsInteractor,
+ powerInteractor = powerInteractor,
shadeDependentFlows = shadeDependentFlows,
animationFlow = keyguardTransitionAnimationFlow,
)
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/navigation/data/repository/NavigationRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/navigation/data/repository/NavigationRepositoryKosmos.kt
new file mode 100644
index 0000000..717a300
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/navigation/data/repository/NavigationRepositoryKosmos.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.navigation.data.repository
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.navigationbar.navigationModeController
+
+val Kosmos.navigationRepository by Fixture {
+ NavigationRepository(
+ controller = navigationModeController,
+ )
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/navigation/domain/interactor/NavigationInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/navigation/domain/interactor/NavigationInteractorKosmos.kt
new file mode 100644
index 0000000..80fe3b9
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/navigation/domain/interactor/NavigationInteractorKosmos.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.navigation.domain.interactor
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.navigation.data.repository.navigationRepository
+
+val Kosmos.navigationInteractor by Fixture {
+ NavigationInteractor(
+ repository = navigationRepository,
+ )
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/navigationbar/NavigationModeControllerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/navigationbar/NavigationModeControllerKosmos.kt
new file mode 100644
index 0000000..f2fb1a8
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/navigationbar/NavigationModeControllerKosmos.kt
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.navigationbar
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.util.mockito.mock
+
+val Kosmos.navigationModeController by Fixture { mock<NavigationModeController>() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/FakeShadeRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/FakeShadeRepository.kt
index 728c67a..4813794 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/FakeShadeRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/FakeShadeRepository.kt
@@ -64,6 +64,8 @@
private val _shadeMode = MutableStateFlow<ShadeMode>(ShadeMode.Single)
override val shadeMode: StateFlow<ShadeMode> = _shadeMode.asStateFlow()
+ override val isDualShadeAlignedToBottom = false
+
@Deprecated("Use ShadeInteractor instead")
override fun setLegacyIsQsExpanded(legacyIsQsExpanded: Boolean) {
_legacyIsQsExpanded.value = legacyIsQsExpanded
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeInteractorKosmos.kt
index 543d5b6..a00d2f4 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeInteractorKosmos.kt
@@ -71,5 +71,6 @@
userSetupRepository = userSetupRepository,
userSwitcherInteractor = userSwitcherInteractor,
baseShadeInteractor = baseShadeInteractor,
+ shadeRepository = shadeRepository,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/OverlayShadeViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/OverlayShadeViewModelKosmos.kt
index fec1028..8d4d547 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/OverlayShadeViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/OverlayShadeViewModelKosmos.kt
@@ -19,11 +19,13 @@
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.scene.domain.interactor.sceneInteractor
+import com.android.systemui.shade.domain.interactor.shadeInteractor
val Kosmos.overlayShadeViewModel: OverlayShadeViewModel by
Kosmos.Fixture {
OverlayShadeViewModel(
applicationScope = applicationCoroutineScope,
sceneInteractor = sceneInteractor,
+ shadeInteractor = shadeInteractor,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt
index 299486f..ffd8aab 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.notification.stack.ui.viewmodel
+import com.android.systemui.communal.domain.interactor.communalSceneInteractor
import com.android.systemui.dump.dumpManager
import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
@@ -86,6 +87,7 @@
primaryBouncerToLockscreenTransitionViewModel =
primaryBouncerToLockscreenTransitionViewModel,
aodBurnInViewModel = aodBurnInViewModel,
+ communalSceneInteractor = communalSceneInteractor,
unfoldTransitionInteractor = unfoldTransitionInteractor,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/util/DeviceConfigProxyKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/util/DeviceConfigProxyKosmos.kt
new file mode 100644
index 0000000..cf902ef
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/util/DeviceConfigProxyKosmos.kt
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.util
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+
+val Kosmos.fakeDeviceConfigProxy by Fixture { DeviceConfigProxyFake() }
+
+val Kosmos.deviceConfigProxy by Fixture<DeviceConfigProxy> { fakeDeviceConfigProxy }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeCastController.java b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeCastController.java
index 84ace7c..5fae38f 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeCastController.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeCastController.java
@@ -18,6 +18,7 @@
import com.android.systemui.statusbar.policy.CastController;
import com.android.systemui.statusbar.policy.CastController.Callback;
+import com.android.systemui.statusbar.policy.CastDevice;
import java.util.ArrayList;
import java.util.List;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index d41de38..022df9a 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -5550,9 +5550,7 @@
for (int i=0; i<intents.length; i++) {
Intent intent = intents[i];
if (intent != null) {
- if (intent.hasFileDescriptors()) {
- throw new IllegalArgumentException("File descriptors passed in Intent");
- }
+ intent.prepareToEnterSystemServer();
if (type == ActivityManager.INTENT_SENDER_BROADCAST &&
(intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
throw new IllegalArgumentException(
@@ -5585,7 +5583,6 @@
}
}
intents[i] = new Intent(intent);
- intents[i].removeExtendedFlags(Intent.EXTENDED_FLAG_FILTER_MISMATCH);
}
}
if (resolvedTypes != null && resolvedTypes.length != intents.length) {
@@ -13961,12 +13958,7 @@
enforceNotIsolatedCaller("startService");
enforceAllowedToStartOrBindServiceIfSdkSandbox(service);
if (service != null) {
- // Refuse possible leaked file descriptors
- if (service.hasFileDescriptors()) {
- throw new IllegalArgumentException("File descriptors passed in Intent");
- }
- // Remove existing mismatch flag so it can be properly updated later
- service.removeExtendedFlags(Intent.EXTENDED_FLAG_FILTER_MISMATCH);
+ service.prepareToEnterSystemServer();
}
if (callingPackage == null) {
@@ -14203,12 +14195,7 @@
enforceAllowedToStartOrBindServiceIfSdkSandbox(service);
if (service != null) {
- // Refuse possible leaked file descriptors
- if (service.hasFileDescriptors()) {
- throw new IllegalArgumentException("File descriptors passed in Intent");
- }
- // Remove existing mismatch flag so it can be properly updated later
- service.removeExtendedFlags(Intent.EXTENDED_FLAG_FILTER_MISMATCH);
+ service.prepareToEnterSystemServer();
}
if (callingPackage == null) {
@@ -16242,12 +16229,7 @@
final Intent verifyBroadcastLocked(Intent intent) {
if (intent != null) {
- // Refuse possible leaked file descriptors
- if (intent.hasFileDescriptors()) {
- throw new IllegalArgumentException("File descriptors passed in Intent");
- }
- // Remove existing mismatch flag so it can be properly updated later
- intent.removeExtendedFlags(Intent.EXTENDED_FLAG_FILTER_MISMATCH);
+ intent.prepareToEnterSystemServer();
}
int flags = intent.getFlags();
@@ -16307,6 +16289,7 @@
String[] excludedPackages, int appOp, Bundle bOptions,
boolean serialized, boolean sticky, int userId) {
enforceNotIsolatedCaller("broadcastIntent");
+
synchronized(this) {
intent = verifyBroadcastLocked(intent);
@@ -16320,6 +16303,12 @@
// Permission regimes around sender-supplied broadcast options.
enforceBroadcastOptionPermissionsInternal(bOptions, callingUid);
+ final ComponentName cn = intent.getComponent();
+
+ Trace.traceBegin(
+ Trace.TRACE_TAG_ACTIVITY_MANAGER,
+ "broadcastIntent:" + (cn != null ? cn.toString() : intent.getAction()));
+
final long origId = Binder.clearCallingIdentity();
try {
return broadcastIntentLocked(callerApp,
@@ -16330,6 +16319,7 @@
callingPid, userId, BackgroundStartPrivileges.NONE, null, null);
} finally {
Binder.restoreCallingIdentity(origId);
+ Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
}
}
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 1ac37ad..0c14a1c 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -130,6 +130,7 @@
import com.android.server.power.stats.BluetoothPowerStatsProcessor;
import com.android.server.power.stats.CameraPowerStatsProcessor;
import com.android.server.power.stats.CpuPowerStatsProcessor;
+import com.android.server.power.stats.CustomEnergyConsumerPowerStatsProcessor;
import com.android.server.power.stats.FlashlightPowerStatsProcessor;
import com.android.server.power.stats.GnssPowerStatsProcessor;
import com.android.server.power.stats.MobileRadioPowerStatsProcessor;
@@ -574,6 +575,15 @@
AggregatedPowerStatsConfig.STATE_PROCESS_STATE)
.setProcessor(
new GnssPowerStatsProcessor(mPowerProfile, mPowerStatsUidResolver));
+
+ config.trackCustomPowerComponents(CustomEnergyConsumerPowerStatsProcessor::new)
+ .trackDeviceStates(
+ AggregatedPowerStatsConfig.STATE_POWER,
+ AggregatedPowerStatsConfig.STATE_SCREEN)
+ .trackUidStates(
+ AggregatedPowerStatsConfig.STATE_POWER,
+ AggregatedPowerStatsConfig.STATE_SCREEN,
+ AggregatedPowerStatsConfig.STATE_PROCESS_STATE);
return config;
}
@@ -665,6 +675,10 @@
BatteryConsumer.POWER_COMPONENT_CAMERA,
Flags.streamlinedMiscBatteryStats());
+ // By convention POWER_COMPONENT_ANY represents custom Energy Consumers
+ mStats.setPowerStatsCollectorEnabled(BatteryConsumer.POWER_COMPONENT_ANY,
+ Flags.streamlinedMiscBatteryStats());
+
mWorker.systemServicesReady();
mStats.systemServicesReady(mContext);
mCpuWakeupStats.systemServicesReady();
diff --git a/services/core/java/com/android/server/audio/AudioServerPermissionProvider.java b/services/core/java/com/android/server/audio/AudioServerPermissionProvider.java
index 76191bb..14eae8d 100644
--- a/services/core/java/com/android/server/audio/AudioServerPermissionProvider.java
+++ b/services/core/java/com/android/server/audio/AudioServerPermissionProvider.java
@@ -16,10 +16,20 @@
package com.android.server.audio;
+import static android.Manifest.permission.ACCESS_ULTRASOUND;
+import static android.Manifest.permission.BLUETOOTH_CONNECT;
import static android.Manifest.permission.CALL_AUDIO_INTERCEPTION;
+import static android.Manifest.permission.CAPTURE_AUDIO_HOTWORD;
+import static android.Manifest.permission.CAPTURE_AUDIO_OUTPUT;
+import static android.Manifest.permission.CAPTURE_MEDIA_OUTPUT;
+import static android.Manifest.permission.CAPTURE_TUNER_AUDIO_INPUT;
+import static android.Manifest.permission.CAPTURE_VOICE_COMMUNICATION_OUTPUT;
import static android.Manifest.permission.MODIFY_AUDIO_ROUTING;
+import static android.Manifest.permission.MODIFY_AUDIO_SETTINGS;
+import static android.Manifest.permission.MODIFY_DEFAULT_AUDIO_EFFECTS;
import static android.Manifest.permission.MODIFY_PHONE_STATE;
import static android.Manifest.permission.RECORD_AUDIO;
+import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
import android.annotation.Nullable;
import android.os.RemoteException;
@@ -52,10 +62,21 @@
static final String[] MONITORED_PERMS = new String[PermissionEnum.ENUM_SIZE];
static {
- MONITORED_PERMS[PermissionEnum.MODIFY_AUDIO_ROUTING] = MODIFY_AUDIO_ROUTING;
- MONITORED_PERMS[PermissionEnum.MODIFY_PHONE_STATE] = MODIFY_PHONE_STATE;
MONITORED_PERMS[PermissionEnum.RECORD_AUDIO] = RECORD_AUDIO;
+ MONITORED_PERMS[PermissionEnum.MODIFY_AUDIO_ROUTING] = MODIFY_AUDIO_ROUTING;
+ MONITORED_PERMS[PermissionEnum.MODIFY_AUDIO_SETTINGS] = MODIFY_AUDIO_SETTINGS;
+ MONITORED_PERMS[PermissionEnum.MODIFY_PHONE_STATE] = MODIFY_PHONE_STATE;
+ MONITORED_PERMS[PermissionEnum.MODIFY_DEFAULT_AUDIO_EFFECTS] = MODIFY_DEFAULT_AUDIO_EFFECTS;
+ MONITORED_PERMS[PermissionEnum.WRITE_SECURE_SETTINGS] = WRITE_SECURE_SETTINGS;
MONITORED_PERMS[PermissionEnum.CALL_AUDIO_INTERCEPTION] = CALL_AUDIO_INTERCEPTION;
+ MONITORED_PERMS[PermissionEnum.ACCESS_ULTRASOUND] = ACCESS_ULTRASOUND;
+ MONITORED_PERMS[PermissionEnum.CAPTURE_AUDIO_OUTPUT] = CAPTURE_AUDIO_OUTPUT;
+ MONITORED_PERMS[PermissionEnum.CAPTURE_MEDIA_OUTPUT] = CAPTURE_MEDIA_OUTPUT;
+ MONITORED_PERMS[PermissionEnum.CAPTURE_AUDIO_HOTWORD] = CAPTURE_AUDIO_HOTWORD;
+ MONITORED_PERMS[PermissionEnum.CAPTURE_TUNER_AUDIO_INPUT] = CAPTURE_TUNER_AUDIO_INPUT;
+ MONITORED_PERMS[PermissionEnum.CAPTURE_VOICE_COMMUNICATION_OUTPUT] =
+ CAPTURE_VOICE_COMMUNICATION_OUTPUT;
+ MONITORED_PERMS[PermissionEnum.BLUETOOTH_CONNECT] = BLUETOOTH_CONNECT;
}
private final Object mLock = new Object();
diff --git a/services/core/java/com/android/server/power/stats/AggregatedPowerStats.java b/services/core/java/com/android/server/power/stats/AggregatedPowerStats.java
index fbdba4f..e27f3b2 100644
--- a/services/core/java/com/android/server/power/stats/AggregatedPowerStats.java
+++ b/services/core/java/com/android/server/power/stats/AggregatedPowerStats.java
@@ -19,16 +19,20 @@
import android.annotation.CurrentTimeMillisLong;
import android.annotation.DurationMillisLong;
import android.annotation.NonNull;
+import android.os.BatteryConsumer;
import android.os.BatteryStats;
+import android.os.PersistableBundle;
import android.os.UserHandle;
import android.text.format.DateFormat;
import android.util.IndentingPrintWriter;
import android.util.Slog;
+import android.util.SparseArray;
import android.util.TimeUtils;
import com.android.internal.os.PowerStats;
import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;
+import com.android.server.power.stats.AggregatedPowerStatsConfig.PowerComponent;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -53,11 +57,14 @@
private static final int MAX_CLOCK_UPDATES = 100;
private static final String XML_TAG_AGGREGATED_POWER_STATS = "agg-power-stats";
- private final PowerComponentAggregatedPowerStats[] mPowerComponentStats;
+ private final AggregatedPowerStatsConfig mConfig;
+ private final SparseArray<PowerComponentAggregatedPowerStats> mPowerComponentStats;
+ private final PowerComponentAggregatedPowerStats mGenericPowerComponent;
static class ClockUpdate {
public long monotonicTime;
- @CurrentTimeMillisLong public long currentTime;
+ @CurrentTimeMillisLong
+ public long currentTime;
}
private final List<ClockUpdate> mClockUpdates = new ArrayList<>();
@@ -65,13 +72,35 @@
@DurationMillisLong
private long mDurationMs;
- AggregatedPowerStats(AggregatedPowerStatsConfig aggregatedPowerStatsConfig) {
- List<AggregatedPowerStatsConfig.PowerComponent> configs =
+ AggregatedPowerStats(@NonNull AggregatedPowerStatsConfig aggregatedPowerStatsConfig) {
+ mConfig = aggregatedPowerStatsConfig;
+ List<PowerComponent> configs =
aggregatedPowerStatsConfig.getPowerComponentsAggregatedStatsConfigs();
- mPowerComponentStats = new PowerComponentAggregatedPowerStats[configs.size()];
+ mPowerComponentStats = new SparseArray<>(configs.size());
for (int i = 0; i < configs.size(); i++) {
- mPowerComponentStats[i] = new PowerComponentAggregatedPowerStats(this, configs.get(i));
+ PowerComponent powerComponent = configs.get(i);
+ mPowerComponentStats.put(powerComponent.getPowerComponentId(),
+ new PowerComponentAggregatedPowerStats(this, powerComponent));
}
+ mGenericPowerComponent = createGenericPowerComponent();
+ mPowerComponentStats.put(BatteryConsumer.POWER_COMPONENT_ANY, mGenericPowerComponent);
+ }
+
+ private PowerComponentAggregatedPowerStats createGenericPowerComponent() {
+ PowerComponent config = new PowerComponent(BatteryConsumer.POWER_COMPONENT_ANY);
+ config.trackDeviceStates(
+ AggregatedPowerStatsConfig.STATE_POWER,
+ AggregatedPowerStatsConfig.STATE_SCREEN)
+ .trackUidStates(
+ AggregatedPowerStatsConfig.STATE_POWER,
+ AggregatedPowerStatsConfig.STATE_SCREEN,
+ AggregatedPowerStatsConfig.STATE_PROCESS_STATE);
+ PowerComponentAggregatedPowerStats stats =
+ new PowerComponentAggregatedPowerStats(this, config);
+ stats.setPowerStatsDescriptor(
+ new PowerStats.Descriptor(BatteryConsumer.POWER_COMPONENT_ANY, 0, null, 0, 0,
+ new PersistableBundle()));
+ return stats;
}
/**
@@ -79,7 +108,7 @@
* there may be multiple clock updates in one set of aggregated stats.
*
* @param monotonicTime monotonic time in milliseconds, see
- * {@link com.android.internal.os.MonotonicClock}
+ * {@link com.android.internal.os.MonotonicClock}
* @param currentTime current time in milliseconds, see {@link System#currentTimeMillis()}
*/
void addClockUpdate(long monotonicTime, @CurrentTimeMillisLong long currentTime) {
@@ -90,7 +119,7 @@
mClockUpdates.add(clockUpdate);
} else {
Slog.i(TAG, "Too many clock updates. Replacing the previous update with "
- + DateFormat.format("yyyy-MM-dd-HH-mm-ss", currentTime));
+ + DateFormat.format("yyyy-MM-dd-HH-mm-ss", currentTime));
mClockUpdates.set(mClockUpdates.size() - 1, clockUpdate);
}
}
@@ -119,66 +148,97 @@
return mDurationMs;
}
- PowerComponentAggregatedPowerStats getPowerComponentStats(int powerComponentId) {
- for (PowerComponentAggregatedPowerStats stats : mPowerComponentStats) {
- if (stats.powerComponentId == powerComponentId) {
- return stats;
+ List<PowerComponentAggregatedPowerStats> getPowerComponentStats() {
+ List<PowerComponentAggregatedPowerStats> list = new ArrayList<>(
+ mPowerComponentStats.size());
+ for (int i = 0; i < mPowerComponentStats.size(); i++) {
+ PowerComponentAggregatedPowerStats stats = mPowerComponentStats.valueAt(i);
+ if (stats != mGenericPowerComponent) {
+ list.add(stats);
}
}
- return null;
+ return list;
+ }
+
+ PowerComponentAggregatedPowerStats getPowerComponentStats(int powerComponentId) {
+ return mPowerComponentStats.get(powerComponentId);
+ }
+
+ void start(long timestampMs) {
+ for (int i = 0; i < mPowerComponentStats.size(); i++) {
+ PowerComponentAggregatedPowerStats component = mPowerComponentStats.valueAt(i);
+ component.getConfig().getProcessor().start(component, timestampMs);
+ }
}
void setDeviceState(@AggregatedPowerStatsConfig.TrackedState int stateId, int state,
long time) {
- for (PowerComponentAggregatedPowerStats stats : mPowerComponentStats) {
- stats.setState(stateId, state, time);
+ for (int i = 0; i < mPowerComponentStats.size(); i++) {
+ mPowerComponentStats.valueAt(i).setState(stateId, state, time);
}
}
void setUidState(int uid, @AggregatedPowerStatsConfig.TrackedState int stateId, int state,
long time) {
- for (PowerComponentAggregatedPowerStats stats : mPowerComponentStats) {
- stats.setUidState(uid, stateId, state, time);
+ for (int i = 0; i < mPowerComponentStats.size(); i++) {
+ mPowerComponentStats.valueAt(i).setUidState(uid, stateId, state, time);
}
}
boolean isCompatible(PowerStats powerStats) {
int powerComponentId = powerStats.descriptor.powerComponentId;
- for (PowerComponentAggregatedPowerStats stats : mPowerComponentStats) {
- if (stats.powerComponentId == powerComponentId && !stats.isCompatible(powerStats)) {
- return false;
- }
- }
- return true;
+ PowerComponentAggregatedPowerStats stats = mPowerComponentStats.get(powerComponentId);
+ return stats != null && stats.isCompatible(powerStats);
}
void addPowerStats(PowerStats powerStats, long time) {
int powerComponentId = powerStats.descriptor.powerComponentId;
- for (PowerComponentAggregatedPowerStats stats : mPowerComponentStats) {
- if (stats.powerComponentId == powerComponentId) {
- stats.getConfig().getProcessor().addPowerStats(stats, powerStats, time);
+ PowerComponentAggregatedPowerStats stats = mPowerComponentStats.get(powerComponentId);
+ if (stats == null) {
+ PowerComponent powerComponent = mConfig.createPowerComponent(powerComponentId);
+ if (powerComponent == null) {
+ return;
}
+
+ stats = new PowerComponentAggregatedPowerStats(this, powerComponent);
+ stats.setPowerStatsDescriptor(powerStats.descriptor);
+ stats.copyStatesFrom(mGenericPowerComponent);
+ mPowerComponentStats.put(powerComponentId, stats);
}
+
+ PowerStatsProcessor processor = stats.getConfig().getProcessor();
+ processor.addPowerStats(stats, powerStats, time);
}
public void noteStateChange(BatteryStats.HistoryItem item) {
- for (PowerComponentAggregatedPowerStats stats : mPowerComponentStats) {
+ for (int i = 0; i < mPowerComponentStats.size(); i++) {
+ PowerComponentAggregatedPowerStats stats = mPowerComponentStats.valueAt(i);
stats.getConfig().getProcessor().noteStateChange(stats, item);
}
}
+ void finish(long timestampMs) {
+ for (int i = 0; i < mPowerComponentStats.size(); i++) {
+ PowerComponentAggregatedPowerStats component = mPowerComponentStats.valueAt(i);
+ component.getConfig().getProcessor().finish(component, timestampMs);
+ }
+ }
+
void reset() {
mClockUpdates.clear();
mDurationMs = 0;
- for (PowerComponentAggregatedPowerStats stats : mPowerComponentStats) {
- stats.reset();
+ for (int i = 0; i < mPowerComponentStats.size(); i++) {
+ mPowerComponentStats.valueAt(i).reset();
}
}
public void writeXml(TypedXmlSerializer serializer) throws IOException {
serializer.startTag(null, XML_TAG_AGGREGATED_POWER_STATS);
- for (PowerComponentAggregatedPowerStats stats : mPowerComponentStats) {
- stats.writeXml(serializer);
+ for (int i = 0; i < mPowerComponentStats.size(); i++) {
+ PowerComponentAggregatedPowerStats stats = mPowerComponentStats.valueAt(i);
+ if (stats != mGenericPowerComponent) {
+ stats.writeXml(serializer);
+ }
}
serializer.endTag(null, XML_TAG_AGGREGATED_POWER_STATS);
serializer.flush();
@@ -200,23 +260,34 @@
case XML_TAG_AGGREGATED_POWER_STATS:
inElement = true;
break;
- case PowerComponentAggregatedPowerStats.XML_TAG_POWER_COMPONENT:
+ case PowerComponentAggregatedPowerStats.XML_TAG_POWER_COMPONENT: {
if (!inElement) {
break;
}
int powerComponentId = parser.getAttributeInt(null,
PowerComponentAggregatedPowerStats.XML_ATTR_ID);
- for (PowerComponentAggregatedPowerStats powerComponent :
- stats.mPowerComponentStats) {
- if (powerComponent.powerComponentId == powerComponentId) {
- if (!powerComponent.readFromXml(parser)) {
- skipToEnd = true;
- }
- break;
+
+ PowerComponentAggregatedPowerStats powerComponentStats =
+ stats.getPowerComponentStats(powerComponentId);
+ if (powerComponentStats == null) {
+ PowerComponent powerComponent =
+ aggregatedPowerStatsConfig.createPowerComponent(
+ powerComponentId);
+ if (powerComponent != null) {
+ powerComponentStats = new PowerComponentAggregatedPowerStats(stats,
+ powerComponent);
+ stats.mPowerComponentStats.put(powerComponentId,
+ powerComponentStats);
+ }
+ }
+ if (powerComponentStats != null) {
+ if (!powerComponentStats.readFromXml(parser)) {
+ skipToEnd = true;
}
}
break;
+ }
}
}
eventType = parser.next();
@@ -254,14 +325,14 @@
ipw.println("Device");
ipw.increaseIndent();
- for (PowerComponentAggregatedPowerStats stats : mPowerComponentStats) {
- stats.dumpDevice(ipw);
+ for (int i = 0; i < mPowerComponentStats.size(); i++) {
+ mPowerComponentStats.valueAt(i).dumpDevice(ipw);
}
ipw.decreaseIndent();
Set<Integer> uids = new HashSet<>();
- for (PowerComponentAggregatedPowerStats stats : mPowerComponentStats) {
- stats.collectUids(uids);
+ for (int i = 0; i < mPowerComponentStats.size(); i++) {
+ mPowerComponentStats.valueAt(i).collectUids(uids);
}
Integer[] allUids = uids.toArray(new Integer[uids.size()]);
@@ -269,8 +340,8 @@
for (int uid : allUids) {
ipw.println(UserHandle.formatUid(uid));
ipw.increaseIndent();
- for (PowerComponentAggregatedPowerStats stats : mPowerComponentStats) {
- stats.dumpUid(ipw, uid);
+ for (int i = 0; i < mPowerComponentStats.size(); i++) {
+ mPowerComponentStats.valueAt(i).dumpUid(ipw, uid);
}
ipw.decreaseIndent();
}
diff --git a/services/core/java/com/android/server/power/stats/AggregatedPowerStatsConfig.java b/services/core/java/com/android/server/power/stats/AggregatedPowerStatsConfig.java
index 1ff7cb7..1f4a391 100644
--- a/services/core/java/com/android/server/power/stats/AggregatedPowerStatsConfig.java
+++ b/services/core/java/com/android/server/power/stats/AggregatedPowerStatsConfig.java
@@ -17,12 +17,14 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.os.BatteryConsumer;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
+import java.util.function.Supplier;
/**
* Configuration that controls how power stats are aggregated. It determines which state changes
@@ -140,7 +142,7 @@
}
@NonNull
- public PowerStatsProcessor getProcessor() {
+ PowerStatsProcessor getProcessor() {
return mProcessor;
}
@@ -160,6 +162,8 @@
}
private final List<PowerComponent> mPowerComponents = new ArrayList<>();
+ private PowerComponent mCustomPowerComponent;
+ private Supplier<PowerStatsProcessor> mCustomPowerStatsProcessorFactory;
/**
* Creates a configuration for the specified power component, which may be one of the
@@ -199,10 +203,45 @@
return powerComponent;
}
+ /**
+ * Creates a configuration for custom power components, which are yet to be discovered
+ * dynamically through the integration with PowerStatsService.
+ */
+ public PowerComponent trackCustomPowerComponents(
+ Supplier<PowerStatsProcessor> processorFactory) {
+ mCustomPowerStatsProcessorFactory = processorFactory;
+ mCustomPowerComponent = new PowerComponent(BatteryConsumer.POWER_COMPONENT_ANY);
+ return mCustomPowerComponent;
+ }
+
+ /**
+ * Returns configurations for all registered or dynamically discovered power components.
+ */
public List<PowerComponent> getPowerComponentsAggregatedStatsConfigs() {
return mPowerComponents;
}
+ /**
+ * Creates a configuration for a custom power component discovered dynamically through the
+ * integration with PowerStatsService.
+ */
+ @Nullable
+ public PowerComponent createPowerComponent(int powerComponentId) {
+ if (mCustomPowerComponent == null) {
+ return null;
+ }
+
+ PowerComponent powerComponent = new PowerComponent(powerComponentId);
+ powerComponent.trackDeviceStates(mCustomPowerComponent.mTrackedDeviceStates);
+ powerComponent.trackUidStates(mCustomPowerComponent.mTrackedUidStates);
+
+ if (mCustomPowerStatsProcessorFactory != null) {
+ powerComponent.setProcessor(mCustomPowerStatsProcessorFactory.get());
+ }
+
+ return powerComponent;
+ }
+
private static final PowerStatsProcessor NO_OP_PROCESSOR = new PowerStatsProcessor() {
@Override
void finish(PowerComponentAggregatedPowerStats stats, long timestampMs) {
diff --git a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
index 322ed86..eabc979 100644
--- a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
+++ b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
@@ -300,6 +300,7 @@
private final BluetoothPowerStatsCollector mBluetoothPowerStatsCollector;
private final CameraPowerStatsCollector mCameraPowerStatsCollector;
private final GnssPowerStatsCollector mGnssPowerStatsCollector;
+ private final CustomEnergyConsumerPowerStatsCollector mCustomEnergyConsumerPowerStatsCollector;
private final SparseBooleanArray mPowerStatsCollectorEnabled = new SparseBooleanArray();
private final WifiPowerStatsCollector.WifiStatsRetriever mWifiStatsRetriever =
new WifiPowerStatsCollector.WifiStatsRetriever() {
@@ -11303,6 +11304,10 @@
mGnssPowerStatsCollector = new GnssPowerStatsCollector(mPowerStatsCollectorInjector);
mGnssPowerStatsCollector.addConsumer(this::recordPowerStats);
+ mCustomEnergyConsumerPowerStatsCollector =
+ new CustomEnergyConsumerPowerStatsCollector(mPowerStatsCollectorInjector);
+ mCustomEnergyConsumerPowerStatsCollector.addConsumer(this::recordPowerStats);
+
mStartCount++;
initTimersAndCounters();
mOnBattery = mOnBatteryInternal = false;
@@ -13922,6 +13927,11 @@
* Read and record Rail Energy data.
*/
public void updateRailStatsLocked() {
+ if (mCustomEnergyConsumerPowerStatsCollector.isEnabled()) {
+ mCustomEnergyConsumerPowerStatsCollector.schedule();
+ return;
+ }
+
if (mEnergyConsumerRetriever == null || !mTmpRailStats.isRailStatsAvailable()) {
return;
}
@@ -14733,6 +14743,10 @@
mPowerStatsCollectorEnabled.get(BatteryConsumer.POWER_COMPONENT_GNSS));
mGnssPowerStatsCollector.schedule();
+ mCustomEnergyConsumerPowerStatsCollector.setEnabled(
+ mPowerStatsCollectorEnabled.get(BatteryConsumer.POWER_COMPONENT_ANY));
+ mCustomEnergyConsumerPowerStatsCollector.schedule();
+
mSystemReady = true;
}
diff --git a/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java b/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java
index ce0ee39..8127b82 100644
--- a/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java
+++ b/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java
@@ -113,7 +113,9 @@
mPowerCalculators.add(new ScreenPowerCalculator(mPowerProfile));
mPowerCalculators.add(new AmbientDisplayPowerCalculator(mPowerProfile));
mPowerCalculators.add(new IdlePowerCalculator(mPowerProfile));
- mPowerCalculators.add(new CustomEnergyConsumerPowerCalculator(mPowerProfile));
+ if (!mPowerStatsExporterEnabled.get(BatteryConsumer.POWER_COMPONENT_ANY)) {
+ mPowerCalculators.add(new CustomEnergyConsumerPowerCalculator(mPowerProfile));
+ }
mPowerCalculators.add(new UserPowerCalculator());
if (!com.android.server.power.optimization.Flags.disableSystemServicePowerAttr()) {
diff --git a/services/core/java/com/android/server/power/stats/BinaryStatePowerStatsLayout.java b/services/core/java/com/android/server/power/stats/BinaryStatePowerStatsLayout.java
index 64c3446..502337c 100644
--- a/services/core/java/com/android/server/power/stats/BinaryStatePowerStatsLayout.java
+++ b/services/core/java/com/android/server/power/stats/BinaryStatePowerStatsLayout.java
@@ -16,16 +16,9 @@
package com.android.server.power.stats;
-class BinaryStatePowerStatsLayout extends PowerStatsLayout {
+class BinaryStatePowerStatsLayout extends EnergyConsumerPowerStatsLayout {
BinaryStatePowerStatsLayout() {
addDeviceSectionUsageDuration();
- // Add a section for consumed energy, even if the specific device does not
- // have support EnergyConsumers. This is done to guarantee format compatibility between
- // PowerStats created by a PowerStatsCollector and those produced by a PowerStatsProcessor.
- addDeviceSectionEnergyConsumers(1);
- addDeviceSectionPowerEstimate();
-
addUidSectionUsageDuration();
- addUidSectionPowerEstimate();
}
}
diff --git a/services/core/java/com/android/server/power/stats/CustomEnergyConsumerPowerStatsCollector.java b/services/core/java/com/android/server/power/stats/CustomEnergyConsumerPowerStatsCollector.java
new file mode 100644
index 0000000..1191901
--- /dev/null
+++ b/services/core/java/com/android/server/power/stats/CustomEnergyConsumerPowerStatsCollector.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.power.stats;
+
+import android.hardware.power.stats.EnergyConsumerType;
+import android.os.BatteryConsumer;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class CustomEnergyConsumerPowerStatsCollector extends PowerStatsCollector {
+ private static final EnergyConsumerPowerStatsLayout sLayout =
+ new EnergyConsumerPowerStatsLayout();
+ private final EnergyConsumerPowerStatsCollector.Injector mInjector;
+ private List<EnergyConsumerPowerStatsCollector> mCollectors;
+
+ CustomEnergyConsumerPowerStatsCollector(EnergyConsumerPowerStatsCollector.Injector injector) {
+ super(injector.getHandler(), 0, injector.getUidResolver(), injector.getClock());
+ mInjector = injector;
+ }
+
+ protected void ensureInitialized() {
+ if (mCollectors != null) {
+ return;
+ }
+
+ ConsumedEnergyRetriever retriever = mInjector.getConsumedEnergyRetriever();
+ int[] energyConsumerIds = retriever.getEnergyConsumerIds(EnergyConsumerType.OTHER);
+ int powerComponentId = BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID;
+ mCollectors = new ArrayList<>(energyConsumerIds.length);
+ for (int i = 0; i < energyConsumerIds.length; i++) {
+ String name = retriever.getEnergyConsumerName(energyConsumerIds[i]);
+ EnergyConsumerPowerStatsCollector collector = new EnergyConsumerPowerStatsCollector(
+ mInjector, powerComponentId++, name, energyConsumerIds[i], sLayout);
+ collector.setEnabled(true);
+ collector.addConsumer(this::deliverStats);
+ mCollectors.add(collector);
+ }
+ }
+
+ @Override
+ public boolean schedule() {
+ if (!isEnabled()) {
+ return false;
+ }
+
+ ensureInitialized();
+ boolean success = false;
+ for (int i = 0; i < mCollectors.size(); i++) {
+ success |= mCollectors.get(i).schedule();
+ }
+ return success;
+ }
+}
diff --git a/services/core/java/com/android/server/power/stats/CustomEnergyConsumerPowerStatsProcessor.java b/services/core/java/com/android/server/power/stats/CustomEnergyConsumerPowerStatsProcessor.java
new file mode 100644
index 0000000..a86242a
--- /dev/null
+++ b/services/core/java/com/android/server/power/stats/CustomEnergyConsumerPowerStatsProcessor.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.power.stats;
+
+import com.android.internal.os.PowerStats;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class CustomEnergyConsumerPowerStatsProcessor extends PowerStatsProcessor {
+ private static final EnergyConsumerPowerStatsLayout sLayout =
+ new EnergyConsumerPowerStatsLayout();
+ private long[] mTmpDeviceStatsArray;
+ private long[] mTmpUidStatsArray;
+ private PowerEstimationPlan mPlan;
+
+ @Override
+ void finish(PowerComponentAggregatedPowerStats stats, long timestampMs) {
+ PowerStats.Descriptor descriptor = stats.getPowerStatsDescriptor();
+ mTmpDeviceStatsArray = new long[descriptor.statsArrayLength];
+ mTmpUidStatsArray = new long[descriptor.uidStatsArrayLength];
+ if (mPlan == null) {
+ mPlan = new PowerEstimationPlan(stats.getConfig());
+ }
+
+ computeDevicePowerEstimates(stats);
+
+ List<Integer> uids = new ArrayList<>();
+ stats.collectUids(uids);
+
+ if (!uids.isEmpty()) {
+ computeUidPowerEstimates(stats, uids);
+ }
+ }
+
+ private void computeDevicePowerEstimates(PowerComponentAggregatedPowerStats stats) {
+ for (int i = mPlan.deviceStateEstimations.size() - 1; i >= 0; i--) {
+ DeviceStateEstimation estimation = mPlan.deviceStateEstimations.get(i);
+ if (!stats.getDeviceStats(mTmpDeviceStatsArray, estimation.stateValues)) {
+ continue;
+ }
+
+ sLayout.setDevicePowerEstimate(mTmpDeviceStatsArray,
+ uCtoMah(sLayout.getConsumedEnergy(mTmpDeviceStatsArray, 0)));
+ stats.setDeviceStats(estimation.stateValues, mTmpDeviceStatsArray);
+ }
+ }
+
+ private void computeUidPowerEstimates(PowerComponentAggregatedPowerStats stats,
+ List<Integer> uids) {
+ for (int i = mPlan.uidStateEstimates.size() - 1; i >= 0; i--) {
+ UidStateEstimate uidStateEstimate = mPlan.uidStateEstimates.get(i);
+ List<UidStateProportionalEstimate> proportionalEstimates =
+ uidStateEstimate.proportionalEstimates;
+ for (int j = proportionalEstimates.size() - 1; j >= 0; j--) {
+ UidStateProportionalEstimate proportionalEstimate = proportionalEstimates.get(j);
+ for (int k = uids.size() - 1; k >= 0; k--) {
+ int uid = uids.get(k);
+ if (stats.getUidStats(mTmpUidStatsArray, uid,
+ proportionalEstimate.stateValues)) {
+ sLayout.setUidPowerEstimate(mTmpUidStatsArray,
+ uCtoMah(sLayout.getUidConsumedEnergy(mTmpUidStatsArray, 0)));
+ stats.setUidStats(uid, proportionalEstimate.stateValues, mTmpUidStatsArray);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/power/stats/EnergyConsumerPowerStatsCollector.java b/services/core/java/com/android/server/power/stats/EnergyConsumerPowerStatsCollector.java
index 2021f85..7f2f729 100644
--- a/services/core/java/com/android/server/power/stats/EnergyConsumerPowerStatsCollector.java
+++ b/services/core/java/com/android/server/power/stats/EnergyConsumerPowerStatsCollector.java
@@ -16,10 +16,13 @@
package com.android.server.power.stats;
+import android.hardware.power.stats.EnergyConsumerAttribution;
+import android.hardware.power.stats.EnergyConsumerResult;
import android.hardware.power.stats.EnergyConsumerType;
import android.os.Handler;
import android.os.PersistableBundle;
import android.util.Slog;
+import android.util.SparseLongArray;
import com.android.internal.os.Clock;
import com.android.internal.os.PowerStats;
@@ -27,9 +30,7 @@
import java.util.function.IntSupplier;
public class EnergyConsumerPowerStatsCollector extends PowerStatsCollector {
- private static final String TAG = "CameraPowerStatsCollector";
-
- private static final long CAMERA_ACTIVITY_REQUEST_TIMEOUT = 20000;
+ private static final String TAG = "EnergyConsumerPowerStatsCollector";
private static final long ENERGY_UNSPECIFIED = -1;
@@ -48,21 +49,22 @@
private final int mEnergyConsumerType;
private final String mEnergyConsumerName;
- private final BinaryStatePowerStatsLayout mLayout;
+ private final EnergyConsumerPowerStatsLayout mLayout;
private boolean mIsInitialized;
private PowerStats mPowerStats;
private ConsumedEnergyRetriever mConsumedEnergyRetriever;
private IntSupplier mVoltageSupplier;
- private int[] mEnergyConsumerIds = new int[0];
+ private int[] mEnergyConsumerIds;
private long mLastConsumedEnergyUws = ENERGY_UNSPECIFIED;
+ private SparseLongArray mLastConsumerEnergyPerUid = new SparseLongArray();
private int mLastVoltageMv;
private long mLastUpdateTimestamp;
private boolean mFirstCollection = true;
EnergyConsumerPowerStatsCollector(Injector injector, int powerComponentId,
String powerComponentName, @EnergyConsumerType int energyConsumerType,
- String energyConsumerName, BinaryStatePowerStatsLayout statsLayout) {
+ String energyConsumerName, EnergyConsumerPowerStatsLayout statsLayout) {
super(injector.getHandler(),
injector.getPowerStatsCollectionThrottlePeriod(powerComponentName),
injector.getUidResolver(), injector.getClock());
@@ -74,6 +76,21 @@
mLayout = statsLayout;
}
+ EnergyConsumerPowerStatsCollector(Injector injector, int powerComponentId,
+ String powerComponentName, int energyConsumerId,
+ EnergyConsumerPowerStatsLayout statsLayout) {
+ super(injector.getHandler(),
+ injector.getPowerStatsCollectionThrottlePeriod(powerComponentName),
+ injector.getUidResolver(), injector.getClock());
+ mInjector = injector;
+ mPowerComponentId = powerComponentId;
+ mPowerComponentName = powerComponentName;
+ mEnergyConsumerIds = new int[]{energyConsumerId};
+ mEnergyConsumerType = EnergyConsumerType.OTHER;
+ mEnergyConsumerName = null;
+ mLayout = statsLayout;
+ }
+
private boolean ensureInitialized() {
if (mIsInitialized) {
return true;
@@ -85,9 +102,10 @@
mConsumedEnergyRetriever = mInjector.getConsumedEnergyRetriever();
mVoltageSupplier = mInjector.getVoltageSupplier();
- mEnergyConsumerIds = mConsumedEnergyRetriever.getEnergyConsumerIds(mEnergyConsumerType,
- mEnergyConsumerName);
-
+ if (mEnergyConsumerIds == null) {
+ mEnergyConsumerIds = mConsumedEnergyRetriever.getEnergyConsumerIds(mEnergyConsumerType,
+ mEnergyConsumerName);
+ }
PersistableBundle extras = new PersistableBundle();
mLayout.toExtras(extras);
PowerStats.Descriptor powerStatsDescriptor = new PowerStats.Descriptor(
@@ -110,18 +128,13 @@
return null;
}
+ EnergyConsumerResult[] energy =
+ mConsumedEnergyRetriever.getConsumedEnergy(mEnergyConsumerIds);
long consumedEnergy = 0;
- int voltageMv = mVoltageSupplier.getAsInt();
- if (voltageMv <= 0) {
- Slog.wtf(TAG, "Unexpected battery voltage (" + voltageMv
- + " mV) when querying energy consumers");
- } else {
- long[] energyUws = mConsumedEnergyRetriever.getConsumedEnergyUws(mEnergyConsumerIds);
- if (energyUws != null) {
- for (int i = energyUws.length - 1; i >= 0; i--) {
- if (energyUws[i] != ENERGY_UNSPECIFIED) {
- consumedEnergy += energyUws[i];
- }
+ if (energy != null) {
+ for (int i = energy.length - 1; i >= 0; i--) {
+ if (energy[i].energyUWs != ENERGY_UNSPECIFIED) {
+ consumedEnergy += energy[i].energyUWs;
}
}
}
@@ -138,13 +151,56 @@
return null;
}
+ int voltageMv = mVoltageSupplier.getAsInt();
+ if (voltageMv <= 0) {
+ Slog.wtf(TAG, "Unexpected battery voltage (" + voltageMv
+ + " mV) when querying energy consumers");
+ voltageMv = 0;
+ }
+
int averageVoltage = mLastVoltageMv != 0 ? (mLastVoltageMv + voltageMv) / 2 : voltageMv;
mLastVoltageMv = voltageMv;
mLayout.setConsumedEnergy(mPowerStats.stats, 0, uJtoUc(energyDelta, averageVoltage));
+
+ for (int i = mPowerStats.uidStats.size() - 1; i >= 0; i--) {
+ mLayout.setUidConsumedEnergy(mPowerStats.uidStats.valueAt(i), 0, 0);
+ }
+
+ if (energy != null) {
+ for (int i = energy.length - 1; i >= 0; i--) {
+ EnergyConsumerAttribution[] perUid = energy[i].attribution;
+ if (perUid == null) {
+ continue;
+ }
+
+ for (EnergyConsumerAttribution attribution : perUid) {
+ int uid = mUidResolver.mapUid(attribution.uid);
+ long lastEnergy = mLastConsumerEnergyPerUid.get(uid);
+ long deltaEnergy = attribution.energyUWs - lastEnergy;
+ mLastConsumerEnergyPerUid.put(uid, attribution.energyUWs);
+ if (deltaEnergy <= 0) {
+ continue;
+ }
+ long[] uidStats = mPowerStats.uidStats.get(uid);
+ if (uidStats == null) {
+ uidStats = new long[mLayout.getUidStatsArrayLength()];
+ mPowerStats.uidStats.put(uid, uidStats);
+ }
+
+ mLayout.setUidConsumedEnergy(uidStats, 0,
+ mLayout.getUidConsumedEnergy(uidStats, 0) + deltaEnergy);
+ }
+ }
+ }
long timestamp = mClock.elapsedRealtime();
mPowerStats.durationMs = timestamp - mLastUpdateTimestamp;
mLastUpdateTimestamp = timestamp;
mFirstCollection = false;
return mPowerStats;
}
+
+ @Override
+ protected void onUidRemoved(int uid) {
+ mLastConsumerEnergyPerUid.delete(uid);
+ }
}
diff --git a/services/core/java/com/android/server/power/stats/EnergyConsumerPowerStatsLayout.java b/services/core/java/com/android/server/power/stats/EnergyConsumerPowerStatsLayout.java
new file mode 100644
index 0000000..8430f56
--- /dev/null
+++ b/services/core/java/com/android/server/power/stats/EnergyConsumerPowerStatsLayout.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.power.stats;
+
+class EnergyConsumerPowerStatsLayout extends PowerStatsLayout {
+ EnergyConsumerPowerStatsLayout() {
+ // Add a section for consumed energy, even if the specific device does not
+ // have support EnergyConsumers. This is done to guarantee format compatibility between
+ // PowerStats created by a PowerStatsCollector and those produced by a PowerStatsProcessor.
+ addDeviceSectionEnergyConsumers(1);
+ addDeviceSectionPowerEstimate();
+
+ // Allocate a cell for per-UID consumed energy attribution. We won't know whether the
+ // corresponding energy consumer does per-UID attribution until we get data from
+ // PowerStatsService.
+ addUidSectionEnergyConsumers(1);
+ addUidSectionPowerEstimate();
+ }
+}
diff --git a/services/core/java/com/android/server/power/stats/PowerComponentAggregatedPowerStats.java b/services/core/java/com/android/server/power/stats/PowerComponentAggregatedPowerStats.java
index 85a2293..8384b2b 100644
--- a/services/core/java/com/android/server/power/stats/PowerComponentAggregatedPowerStats.java
+++ b/services/core/java/com/android/server/power/stats/PowerComponentAggregatedPowerStats.java
@@ -22,6 +22,7 @@
import android.annotation.Nullable;
import android.os.UserHandle;
import android.util.IndentingPrintWriter;
+import android.util.Slog;
import android.util.SparseArray;
import com.android.internal.os.PowerStats;
@@ -44,6 +45,7 @@
* as part of the {@link PowerStats.Descriptor}.
*/
class PowerComponentAggregatedPowerStats {
+ private static final String TAG = "AggregatePowerStats";
static final String XML_TAG_POWER_COMPONENT = "power_component";
static final String XML_ATTR_ID = "id";
private static final String XML_TAG_DEVICE_STATS = "device-stats";
@@ -372,6 +374,37 @@
}
}
+ void copyStatesFrom(PowerComponentAggregatedPowerStats source) {
+ if (source.mDeviceStates.length == mDeviceStates.length) {
+ System.arraycopy(source.mDeviceStates, 0, mDeviceStates, 0, mDeviceStates.length);
+ if (source.mDeviceStats != null) {
+ createDeviceStats(0);
+ if (mDeviceStats != null) {
+ mDeviceStats.copyStatesFrom(source.mDeviceStats);
+ }
+ }
+ } else {
+ Slog.wtf(TAG, "State configurations have different lengths: "
+ + source.mDeviceStates.length + " vs " + mDeviceStates.length);
+ }
+ for (int i = source.mUidStats.size() - 1; i >= 0; i--) {
+ int uid = source.mUidStats.keyAt(i);
+ UidStats sourceUidStats = source.mUidStats.valueAt(i);
+ if (sourceUidStats.states == null) {
+ continue;
+ }
+ UidStats uidStats = new UidStats();
+ uidStats.states = Arrays.copyOf(sourceUidStats.states, sourceUidStats.states.length);
+ if (sourceUidStats.stats != null) {
+ createUidStats(uidStats, 0);
+ if (uidStats.stats != null) {
+ uidStats.stats.copyStatesFrom(sourceUidStats.stats);
+ }
+ }
+ mUidStats.put(uid, uidStats);
+ }
+ }
+
public void writeXml(TypedXmlSerializer serializer) throws IOException {
// No stats aggregated - can skip writing XML altogether
if (mPowerStatsDescriptor == null) {
diff --git a/services/core/java/com/android/server/power/stats/PowerStatsAggregator.java b/services/core/java/com/android/server/power/stats/PowerStatsAggregator.java
index 6e7fdf1..86f515c 100644
--- a/services/core/java/com/android/server/power/stats/PowerStatsAggregator.java
+++ b/services/core/java/com/android/server/power/stats/PowerStatsAggregator.java
@@ -15,8 +15,8 @@
*/
package com.android.server.power.stats;
+import android.annotation.NonNull;
import android.os.BatteryStats;
-import android.util.SparseArray;
import com.android.internal.os.BatteryStatsHistory;
import com.android.internal.os.BatteryStatsHistoryIterator;
@@ -32,20 +32,14 @@
private static final long UNINITIALIZED = -1;
private final AggregatedPowerStatsConfig mAggregatedPowerStatsConfig;
private final BatteryStatsHistory mHistory;
- private final SparseArray<PowerStatsProcessor> mProcessors = new SparseArray<>();
private AggregatedPowerStats mStats;
private int mCurrentBatteryState = AggregatedPowerStatsConfig.POWER_STATE_BATTERY;
private int mCurrentScreenState = AggregatedPowerStatsConfig.SCREEN_STATE_OTHER;
- public PowerStatsAggregator(AggregatedPowerStatsConfig aggregatedPowerStatsConfig,
- BatteryStatsHistory history) {
+ public PowerStatsAggregator(@NonNull AggregatedPowerStatsConfig aggregatedPowerStatsConfig,
+ @NonNull BatteryStatsHistory history) {
mAggregatedPowerStatsConfig = aggregatedPowerStatsConfig;
mHistory = history;
- for (AggregatedPowerStatsConfig.PowerComponent powerComponentsConfig :
- aggregatedPowerStatsConfig.getPowerComponentsAggregatedStatsConfigs()) {
- PowerStatsProcessor processor = powerComponentsConfig.getProcessor();
- mProcessors.put(powerComponentsConfig.getPowerComponentId(), processor);
- }
}
AggregatedPowerStatsConfig getConfig() {
@@ -71,7 +65,7 @@
mStats = new AggregatedPowerStats(mAggregatedPowerStatsConfig);
}
- start(mStats, startTimeMs);
+ mStats.start(startTimeMs);
boolean clockUpdateAdded = false;
long baseTime = startTimeMs > 0 ? startTimeMs : UNINITIALIZED;
@@ -138,7 +132,7 @@
if (!mStats.isCompatible(item.powerStats)) {
if (lastTime > baseTime) {
mStats.setDuration(lastTime - baseTime);
- finish(mStats, lastTime);
+ mStats.finish(lastTime);
consumer.accept(mStats);
}
mStats.reset();
@@ -151,7 +145,7 @@
}
if (lastTime > baseTime) {
mStats.setDuration(lastTime - baseTime);
- finish(mStats, lastTime);
+ mStats.finish(lastTime);
consumer.accept(mStats);
}
@@ -159,26 +153,6 @@
}
}
- private void start(AggregatedPowerStats stats, long timestampMs) {
- for (int i = 0; i < mProcessors.size(); i++) {
- PowerComponentAggregatedPowerStats component =
- stats.getPowerComponentStats(mProcessors.keyAt(i));
- if (component != null) {
- mProcessors.valueAt(i).start(component, timestampMs);
- }
- }
- }
-
- private void finish(AggregatedPowerStats stats, long timestampMs) {
- for (int i = 0; i < mProcessors.size(); i++) {
- PowerComponentAggregatedPowerStats component =
- stats.getPowerComponentStats(mProcessors.keyAt(i));
- if (component != null) {
- mProcessors.valueAt(i).finish(component, timestampMs);
- }
- }
- }
-
/**
* Reset to prepare for a new aggregation session.
*/
diff --git a/services/core/java/com/android/server/power/stats/PowerStatsCollector.java b/services/core/java/com/android/server/power/stats/PowerStatsCollector.java
index d442c61..d9f6c1f 100644
--- a/services/core/java/com/android/server/power/stats/PowerStatsCollector.java
+++ b/services/core/java/com/android/server/power/stats/PowerStatsCollector.java
@@ -16,6 +16,7 @@
package com.android.server.power.stats;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.hardware.power.stats.EnergyConsumer;
import android.hardware.power.stats.EnergyConsumerResult;
@@ -61,7 +62,6 @@
private long mLastScheduledUpdateMs = -1;
@GuardedBy("this")
- @SuppressWarnings("unchecked")
private volatile List<Consumer<PowerStats>> mConsumerList = Collections.emptyList();
public PowerStatsCollector(Handler handler, long throttlePeriodMs,
@@ -90,7 +90,6 @@
* Adds a consumer that will receive a callback every time a snapshot of stats is collected.
* The method is thread safe.
*/
- @SuppressWarnings("unchecked")
public void addConsumer(Consumer<PowerStats> consumer) {
synchronized (this) {
if (mConsumerList.contains(consumer)) {
@@ -107,7 +106,6 @@
* Removes a consumer.
* The method is thread safe.
*/
- @SuppressWarnings("unchecked")
public void removeConsumer(Consumer<PowerStats> consumer) {
synchronized (this) {
List<Consumer<PowerStats>> newList = new ArrayList<>(mConsumerList);
@@ -131,18 +129,6 @@
return mEnabled;
}
- @SuppressWarnings("GuardedBy") // Field is volatile
- public void collectAndDeliverStats() {
- PowerStats stats = collectStats();
- if (stats == null) {
- return;
- }
- List<Consumer<PowerStats>> consumerList = mConsumerList;
- for (int i = consumerList.size() - 1; i >= 0; i--) {
- consumerList.get(i).accept(stats);
- }
- }
-
/**
* Schedules a stats snapshot collection, throttled in accordance with the
* {@link #mThrottlePeriodMs} parameter.
@@ -175,8 +161,30 @@
return true;
}
+ /**
+ * Performs a PowerStats collection pass and delivers the result to registered consumers.
+ */
+ @SuppressWarnings("GuardedBy") // Field is volatile
+ public void collectAndDeliverStats() {
+ deliverStats(collectStats());
+ }
+
@Nullable
- protected abstract PowerStats collectStats();
+ protected PowerStats collectStats() {
+ return null;
+ }
+
+ @SuppressWarnings("GuardedBy") // Field is volatile
+ protected void deliverStats(PowerStats stats) {
+ if (stats == null) {
+ return;
+ }
+
+ List<Consumer<PowerStats>> consumerList = mConsumerList;
+ for (int i = consumerList.size() - 1; i >= 0; i--) {
+ consumerList.get(i).accept(stats);
+ }
+ }
/**
* Collects a fresh stats snapshot and prints it to the supplied printer.
@@ -231,10 +239,33 @@
}
interface ConsumedEnergyRetriever {
+ @NonNull
int[] getEnergyConsumerIds(@EnergyConsumerType int energyConsumerType, String name);
+ String getEnergyConsumerName(int energyConsumerId);
+
@Nullable
- long[] getConsumedEnergyUws(int[] energyConsumerIds);
+ EnergyConsumerResult[] getConsumedEnergy(int[] energyConsumerIds);
+
+ @Nullable
+ default long[] getConsumedEnergyUws(int[] energyConsumerIds) {
+ EnergyConsumerResult[] results = getConsumedEnergy(energyConsumerIds);
+ if (results == null) {
+ return null;
+ }
+
+ long[] energy = new long[energyConsumerIds.length];
+ for (int i = 0; i < energyConsumerIds.length; i++) {
+ int id = energyConsumerIds[i];
+ for (EnergyConsumerResult result : results) {
+ if (result.id == id) {
+ energy[i] = result.energyUWs;
+ break;
+ }
+ }
+ }
+ return energy;
+ }
default int[] getEnergyConsumerIds(@EnergyConsumerType int energyConsumerType) {
return getEnergyConsumerIds(energyConsumerType, null);
@@ -243,24 +274,38 @@
static class ConsumedEnergyRetrieverImpl implements ConsumedEnergyRetriever {
private final PowerStatsInternal mPowerStatsInternal;
+ private EnergyConsumer[] mEnergyConsumers;
ConsumedEnergyRetrieverImpl(PowerStatsInternal powerStatsInternal) {
mPowerStatsInternal = powerStatsInternal;
}
- @Override
- public int[] getEnergyConsumerIds(int energyConsumerType, String name) {
- if (mPowerStatsInternal == null) {
- return new int[0];
+ private void ensureEnergyConsumers() {
+ if (mEnergyConsumers != null) {
+ return;
}
- EnergyConsumer[] energyConsumerInfo = mPowerStatsInternal.getEnergyConsumerInfo();
- if (energyConsumerInfo == null) {
+ if (mPowerStatsInternal == null) {
+ mEnergyConsumers = new EnergyConsumer[0];
+ return;
+ }
+
+ mEnergyConsumers = mPowerStatsInternal.getEnergyConsumerInfo();
+ if (mEnergyConsumers == null) {
+ mEnergyConsumers = new EnergyConsumer[0];
+ }
+ }
+
+ @Override
+ public int[] getEnergyConsumerIds(int energyConsumerType, String name) {
+ ensureEnergyConsumers();
+
+ if (mEnergyConsumers.length == 0) {
return new int[0];
}
List<EnergyConsumer> energyConsumers = new ArrayList<>();
- for (EnergyConsumer energyConsumer : energyConsumerInfo) {
+ for (EnergyConsumer energyConsumer : mEnergyConsumers) {
if (energyConsumer.type == energyConsumerType
&& (name == null || name.equals(energyConsumer.name))) {
energyConsumers.add(energyConsumer);
@@ -280,32 +325,50 @@
}
@Override
- public long[] getConsumedEnergyUws(int[] energyConsumerIds) {
+ public EnergyConsumerResult[] getConsumedEnergy(int[] energyConsumerIds) {
CompletableFuture<EnergyConsumerResult[]> future =
mPowerStatsInternal.getEnergyConsumedAsync(energyConsumerIds);
- EnergyConsumerResult[] results = null;
try {
- results = future.get(
- POWER_STATS_ENERGY_CONSUMERS_TIMEOUT, TimeUnit.MILLISECONDS);
+ return future.get(POWER_STATS_ENERGY_CONSUMERS_TIMEOUT, TimeUnit.MILLISECONDS);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
Slog.e(TAG, "Could not obtain energy consumers from PowerStatsService", e);
}
- if (results == null) {
- return null;
- }
+ return null;
+ }
- long[] energy = new long[energyConsumerIds.length];
- for (int i = 0; i < energyConsumerIds.length; i++) {
- int id = energyConsumerIds[i];
- for (EnergyConsumerResult result : results) {
- if (result.id == id) {
- energy[i] = result.energyUWs;
- break;
- }
+ @Override
+ public String getEnergyConsumerName(int energyConsumerId) {
+ ensureEnergyConsumers();
+
+ for (EnergyConsumer energyConsumer : mEnergyConsumers) {
+ if (energyConsumer.id == energyConsumerId) {
+ return sanitizeCustomPowerComponentName(energyConsumer);
}
}
- return energy;
+
+ Slog.e(TAG, "Unsupported energy consumer ID " + energyConsumerId);
+ return "unsupported";
+ }
+
+ private String sanitizeCustomPowerComponentName(EnergyConsumer energyConsumer) {
+ String name = energyConsumer.name;
+ if (name == null || name.isBlank()) {
+ name = "CUSTOM_" + energyConsumer.id;
+ }
+ int length = name.length();
+ StringBuilder sb = new StringBuilder(length);
+ for (int i = 0; i < length; i++) {
+ char c = name.charAt(i);
+ if (Character.isWhitespace(c)) {
+ sb.append(' ');
+ } else if (Character.isISOControl(c)) {
+ sb.append('_');
+ } else {
+ sb.append(c);
+ }
+ }
+ return sb.toString();
}
}
}
diff --git a/services/core/java/com/android/server/power/stats/PowerStatsExporter.java b/services/core/java/com/android/server/power/stats/PowerStatsExporter.java
index f6b198a8..4bba649 100644
--- a/services/core/java/com/android/server/power/stats/PowerStatsExporter.java
+++ b/services/core/java/com/android/server/power/stats/PowerStatsExporter.java
@@ -115,25 +115,16 @@
private void populateBatteryUsageStatsBuilder(
BatteryUsageStats.Builder batteryUsageStatsBuilder, AggregatedPowerStats stats) {
- AggregatedPowerStatsConfig config = mPowerStatsAggregator.getConfig();
- List<AggregatedPowerStatsConfig.PowerComponent> powerComponents =
- config.getPowerComponentsAggregatedStatsConfigs();
- for (int i = powerComponents.size() - 1; i >= 0; i--) {
- populateBatteryUsageStatsBuilder(batteryUsageStatsBuilder, stats,
- powerComponents.get(i));
+ List<PowerComponentAggregatedPowerStats> powerComponentStats =
+ stats.getPowerComponentStats();
+ for (int i = powerComponentStats.size() - 1; i >= 0; i--) {
+ populateBatteryUsageStatsBuilder(batteryUsageStatsBuilder, powerComponentStats.get(i));
}
}
- private void populateBatteryUsageStatsBuilder(
- BatteryUsageStats.Builder batteryUsageStatsBuilder, AggregatedPowerStats stats,
- AggregatedPowerStatsConfig.PowerComponent powerComponent) {
- int powerComponentId = powerComponent.getPowerComponentId();
- PowerComponentAggregatedPowerStats powerComponentStats = stats.getPowerComponentStats(
- powerComponentId);
- if (powerComponentStats == null) {
- return;
- }
-
+ private static void populateBatteryUsageStatsBuilder(
+ BatteryUsageStats.Builder batteryUsageStatsBuilder,
+ PowerComponentAggregatedPowerStats powerComponentStats) {
PowerStats.Descriptor descriptor = powerComponentStats.getPowerStatsDescriptor();
if (descriptor == null) {
return;
@@ -144,7 +135,8 @@
long[] deviceStats = new long[descriptor.statsArrayLength];
double[] totalPower = new double[1];
- MultiStateStats.States.forEachTrackedStateCombination(powerComponent.getDeviceStateConfig(),
+ MultiStateStats.States.forEachTrackedStateCombination(
+ powerComponentStats.getConfig().getDeviceStateConfig(),
states -> {
if (states[AggregatedPowerStatsConfig.STATE_POWER]
!= AggregatedPowerStatsConfig.POWER_STATE_BATTERY) {
@@ -161,29 +153,34 @@
AggregateBatteryConsumer.Builder deviceScope =
batteryUsageStatsBuilder.getAggregateBatteryConsumerBuilder(
BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE);
- deviceScope.addConsumedPower(powerComponentId,
- totalPower[0], BatteryConsumer.POWER_MODEL_UNDEFINED);
+ if (descriptor.powerComponentId >= BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID) {
+ deviceScope.addConsumedPowerForCustomComponent(descriptor.powerComponentId,
+ totalPower[0]);
+ } else {
+ deviceScope.addConsumedPower(descriptor.powerComponentId,
+ totalPower[0], BatteryConsumer.POWER_MODEL_UNDEFINED);
+ }
if (layout.isUidPowerAttributionSupported()) {
- populateUidBatteryConsumers(batteryUsageStatsBuilder, powerComponent,
+ populateUidBatteryConsumers(batteryUsageStatsBuilder,
powerComponentStats, layout);
}
}
private static void populateUidBatteryConsumers(
BatteryUsageStats.Builder batteryUsageStatsBuilder,
- AggregatedPowerStatsConfig.PowerComponent powerComponent,
PowerComponentAggregatedPowerStats powerComponentStats,
PowerStatsLayout layout) {
+ AggregatedPowerStatsConfig.PowerComponent powerComponent = powerComponentStats.getConfig();
int powerComponentId = powerComponent.getPowerComponentId();
PowerStats.Descriptor descriptor = powerComponentStats.getPowerStatsDescriptor();
long[] uidStats = new long[descriptor.uidStatsArrayLength];
- boolean breakDownByProcState =
- batteryUsageStatsBuilder.isProcessStateDataNeeded()
+ // TODO(b/347101393): add support for per-procstate breakdown for custom energy consumers
+ boolean breakDownByProcState = batteryUsageStatsBuilder.isProcessStateDataNeeded()
&& powerComponent
- .getUidStateConfig()[AggregatedPowerStatsConfig.STATE_PROCESS_STATE]
- .isTracked();
+ .getUidStateConfig()[AggregatedPowerStatsConfig.STATE_PROCESS_STATE].isTracked()
+ && powerComponentId < BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID;
double[] powerByProcState =
new double[breakDownByProcState ? BatteryConsumer.PROCESS_STATE_COUNT : 1];
@@ -224,19 +221,27 @@
powerAllProcStates += power;
if (breakDownByProcState
&& procState != BatteryConsumer.PROCESS_STATE_UNSPECIFIED) {
- builder.addConsumedPower(builder.getKey(powerComponentId, procState),
- power, BatteryConsumer.POWER_MODEL_UNDEFINED);
+ builder.addConsumedPower(builder.getKey(powerComponentId, procState), power,
+ BatteryConsumer.POWER_MODEL_UNDEFINED);
}
}
- builder.addConsumedPower(powerComponentId, powerAllProcStates,
- BatteryConsumer.POWER_MODEL_UNDEFINED);
+ if (powerComponentId >= BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID) {
+ builder.addConsumedPowerForCustomComponent(powerComponentId, powerAllProcStates);
+ } else {
+ builder.addConsumedPower(powerComponentId, powerAllProcStates,
+ BatteryConsumer.POWER_MODEL_UNDEFINED);
+ }
powerAllApps += powerAllProcStates;
}
AggregateBatteryConsumer.Builder allAppsScope =
batteryUsageStatsBuilder.getAggregateBatteryConsumerBuilder(
BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS);
- allAppsScope.addConsumedPower(powerComponentId, powerAllApps,
- BatteryConsumer.POWER_MODEL_UNDEFINED);
+ if (powerComponentId >= BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID) {
+ allAppsScope.addConsumedPowerForCustomComponent(powerComponentId, powerAllApps);
+ } else {
+ allAppsScope.addConsumedPower(powerComponentId, powerAllApps,
+ BatteryConsumer.POWER_MODEL_UNDEFINED);
+ }
}
}
diff --git a/services/core/java/com/android/server/power/stats/PowerStatsLayout.java b/services/core/java/com/android/server/power/stats/PowerStatsLayout.java
index 9624fd2..62abfc6 100644
--- a/services/core/java/com/android/server/power/stats/PowerStatsLayout.java
+++ b/services/core/java/com/android/server/power/stats/PowerStatsLayout.java
@@ -32,6 +32,8 @@
private static final String EXTRA_DEVICE_ENERGY_CONSUMERS_POSITION = "de";
private static final String EXTRA_DEVICE_ENERGY_CONSUMERS_COUNT = "dec";
private static final String EXTRA_UID_DURATION_POSITION = "ud";
+ private static final String EXTRA_UID_ENERGY_CONSUMERS_POSITION = "ue";
+ private static final String EXTRA_UID_ENERGY_CONSUMERS_COUNT = "uec";
private static final String EXTRA_UID_POWER_POSITION = "up";
protected static final int UNSUPPORTED = -1;
@@ -53,6 +55,8 @@
private int mDeviceEnergyConsumerCount;
private int mDevicePowerEstimatePosition = UNSUPPORTED;
private int mUidDurationPosition = UNSUPPORTED;
+ private int mUidEnergyConsumerPosition = UNSUPPORTED;
+ private int mUidEnergyConsumerCount;
private int mUidPowerEstimatePosition = UNSUPPORTED;
public PowerStatsLayout() {
@@ -244,6 +248,36 @@
}
/**
+ * Declares that the UID stats array has a section capturing EnergyConsumer data from
+ * PowerStatsService.
+ */
+ public void addUidSectionEnergyConsumers(int energyConsumerCount) {
+ mUidEnergyConsumerPosition = addUidSection(energyConsumerCount, "energy",
+ FLAG_OPTIONAL);
+ mUidEnergyConsumerCount = energyConsumerCount;
+ }
+
+ public int getUidEnergyConsumerCount() {
+ return mUidEnergyConsumerCount;
+ }
+
+ /**
+ * Saves the accumulated energy for the specified rail the corresponding
+ * <code>stats</code> element.
+ */
+ public void setUidConsumedEnergy(long[] stats, int index, long energy) {
+ stats[mUidEnergyConsumerPosition + index] = energy;
+ }
+
+ /**
+ * Extracts the EnergyConsumer data from a uid stats array for the specified
+ * EnergyConsumer.
+ */
+ public long getUidConsumedEnergy(long[] stats, int index) {
+ return stats[mUidEnergyConsumerPosition + index];
+ }
+
+ /**
* Converts the supplied mAh power estimate to a long and saves it in the corresponding
* element of <code>stats</code>.
*/
@@ -269,6 +303,8 @@
mDeviceEnergyConsumerCount);
extras.putInt(EXTRA_DEVICE_POWER_POSITION, mDevicePowerEstimatePosition);
extras.putInt(EXTRA_UID_DURATION_POSITION, mUidDurationPosition);
+ extras.putInt(EXTRA_UID_ENERGY_CONSUMERS_POSITION, mUidEnergyConsumerPosition);
+ extras.putInt(EXTRA_UID_ENERGY_CONSUMERS_COUNT, mUidEnergyConsumerCount);
extras.putInt(EXTRA_UID_POWER_POSITION, mUidPowerEstimatePosition);
extras.putString(PowerStats.Descriptor.EXTRA_DEVICE_STATS_FORMAT, mDeviceFormat.toString());
extras.putString(PowerStats.Descriptor.EXTRA_STATE_STATS_FORMAT, mStateFormat.toString());
@@ -284,6 +320,8 @@
mDeviceEnergyConsumerCount = extras.getInt(EXTRA_DEVICE_ENERGY_CONSUMERS_COUNT);
mDevicePowerEstimatePosition = extras.getInt(EXTRA_DEVICE_POWER_POSITION);
mUidDurationPosition = extras.getInt(EXTRA_UID_DURATION_POSITION);
+ mUidEnergyConsumerPosition = extras.getInt(EXTRA_UID_ENERGY_CONSUMERS_POSITION);
+ mUidEnergyConsumerCount = extras.getInt(EXTRA_UID_ENERGY_CONSUMERS_COUNT);
mUidPowerEstimatePosition = extras.getInt(EXTRA_UID_POWER_POSITION);
}
diff --git a/services/core/java/com/android/server/power/stats/PowerStatsProcessor.java b/services/core/java/com/android/server/power/stats/PowerStatsProcessor.java
index f257e1a..dfc8daa 100644
--- a/services/core/java/com/android/server/power/stats/PowerStatsProcessor.java
+++ b/services/core/java/com/android/server/power/stats/PowerStatsProcessor.java
@@ -43,7 +43,7 @@
* 2. For each UID, compute the proportion of the combined estimates in each state
* and attribute the corresponding portion of the total power estimate in that state to the UID.
*/
-abstract class PowerStatsProcessor {
+public abstract class PowerStatsProcessor {
private static final String TAG = "PowerStatsProcessor";
private static final double MILLIAMPHOUR_PER_MICROCOULOMB = 1.0 / 1000.0 / 60.0 / 60.0;
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index abc6bf6..b89120b 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -17,6 +17,7 @@
package com.android.server.wallpaper;
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+import static android.Manifest.permission.MANAGE_EXTERNAL_STORAGE;
import static android.Manifest.permission.READ_WALLPAPER_INTERNAL;
import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
import static android.app.WallpaperManager.COMMAND_REAPPLY;
@@ -100,7 +101,6 @@
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
-import android.os.storage.StorageManager;
import android.service.wallpaper.IWallpaperConnection;
import android.service.wallpaper.IWallpaperEngine;
import android.service.wallpaper.IWallpaperService;
@@ -2207,10 +2207,7 @@
IWallpaperManagerCallback cb, final int which, Bundle outParams, int wallpaperUserId,
boolean getCropped) {
final boolean hasPrivilege = hasPermission(READ_WALLPAPER_INTERNAL);
- if (!hasPrivilege) {
- mContext.getSystemService(StorageManager.class).checkPermissionReadImages(true,
- Binder.getCallingPid(), Binder.getCallingUid(), callingPkg, callingFeatureId);
- }
+ if (!hasPrivilege) checkPermission(MANAGE_EXTERNAL_STORAGE);
wallpaperUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
Binder.getCallingUid(), wallpaperUserId, false, true, "getWallpaper", null);
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index d9dc7ba..10243a7 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -6245,12 +6245,13 @@
return false;
}
- // Check if there are any activities with different UID over the activity that is embedded
- // in untrusted mode. Traverse bottom to top with boundary so that it will only check
- // activities above this activity.
+ // Check if there are any activities with different UID occluding partially the activity
+ // that is embedded in untrusted mode. Traverse bottom to top with boundary so that it will
+ // only check activities above this activity.
final ActivityRecord differentUidOverlayActivity = getTask().getActivity(
- a -> !a.finishing && a.getUid() != getUid(), this /* boundary */,
- false /* includeBoundary */, false /* traverseTopToBottom */);
+ a -> !a.finishing && a.getUid() != getUid() && Rect.intersects(a.getBounds(),
+ getBounds()), this /* boundary */, false /* includeBoundary */,
+ false /* traverseTopToBottom */);
return differentUidOverlayActivity != null;
}
@@ -6563,7 +6564,12 @@
// Schedule an idle timeout in case the app doesn't do it for us.
mTaskSupervisor.scheduleIdleTimeout(this);
- mTaskSupervisor.reportResumedActivityLocked(this);
+ mTaskSupervisor.mStoppingActivities.remove(this);
+ if (getDisplayArea().allResumedActivitiesComplete()) {
+ // Construct the compat environment at a relatively stable state if needed.
+ updateCompatDisplayInsets();
+ mRootWindowContainer.executeAppTransitionForAllDisplay();
+ }
resumeKeyDispatchingLocked();
final Task rootTask = getRootTask();
@@ -10302,7 +10308,7 @@
if (rootTask != null && rootTask.mTranslucentActivityWaiting == this) {
rootTask.checkTranslucentActivityWaiting(null);
}
- final boolean andResume = shouldBeResumed(null /*activeActivity*/);
+ final boolean andResume = isState(RESUMED) || shouldBeResumed(null /*activeActivity*/);
List<ResultInfo> pendingResults = null;
List<ReferrerIntent> pendingNewIntents = null;
if (andResume) {
diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java
index 0e401eb..a0ef030 100644
--- a/services/core/java/com/android/server/wm/ActivityStartController.java
+++ b/services/core/java/com/android/server/wm/ActivityStartController.java
@@ -424,19 +424,13 @@
Intent intent = intents[i];
NeededUriGrants intentGrants = null;
- // Refuse possible leaked file descriptors.
- if (intent.hasFileDescriptors()) {
- throw new IllegalArgumentException("File descriptors passed in Intent");
- }
+ intent.prepareToEnterSystemServer();
// Get the flag earlier because the intent may be modified in resolveActivity below.
final boolean componentSpecified = intent.getComponent() != null;
// Don't modify the client's object!
intent = new Intent(intent);
- // Remove existing mismatch flag so it can be properly updated later
- intent.removeExtendedFlags(Intent.EXTENDED_FLAG_FILTER_MISMATCH);
-
// Collect information about the target of the Intent.
ActivityInfo aInfo = mSupervisor.resolveActivity(intent, resolvedTypes[i],
0 /* startFlags */, null /* profilerInfo */, userId, filterCallingUid,
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index e6d8132..e9c08e0 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -718,13 +718,7 @@
onExecutionStarted();
if (mRequest.intent != null) {
- // Refuse possible leaked file descriptors
- if (mRequest.intent.hasFileDescriptors()) {
- throw new IllegalArgumentException("File descriptors passed in Intent");
- }
-
- // Remove existing mismatch flag so it can be properly updated later
- mRequest.intent.removeExtendedFlags(Intent.EXTENDED_FLAG_FILTER_MISMATCH);
+ mRequest.intent.prepareToEnterSystemServer();
}
final LaunchingState launchingState;
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index cfd5300..2109f5d 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -1318,12 +1318,7 @@
String resultWho, int requestCode, int flagsMask, int flagsValues, Bundle bOptions) {
enforceNotIsolatedCaller("startActivityIntentSender");
if (fillInIntent != null) {
- // Refuse possible leaked file descriptors
- if (fillInIntent.hasFileDescriptors()) {
- throw new IllegalArgumentException("File descriptors passed in Intent");
- }
- // Remove existing mismatch flag so it can be properly updated later
- fillInIntent.removeExtendedFlags(Intent.EXTENDED_FLAG_FILTER_MISMATCH);
+ fillInIntent.prepareToEnterSystemServer();
}
if (!(target instanceof PendingIntentRecord)) {
@@ -1349,10 +1344,10 @@
@Override
public boolean startNextMatchingActivity(IBinder callingActivity, Intent intent,
Bundle bOptions) {
- // Refuse possible leaked file descriptors
- if (intent != null && intent.hasFileDescriptors()) {
- throw new IllegalArgumentException("File descriptors passed in Intent");
+ if (intent != null) {
+ intent.prepareToEnterSystemServer();
}
+
SafeActivityOptions options = SafeActivityOptions.fromBundle(bOptions);
synchronized (mGlobalLock) {
@@ -1367,8 +1362,6 @@
return false;
}
intent = new Intent(intent);
- // Remove existing mismatch flag so it can be properly updated later
- intent.removeExtendedFlags(Intent.EXTENDED_FLAG_FILTER_MISMATCH);
// The caller is not allowed to change the data.
intent.setDataAndType(r.intent.getData(), r.intent.getType());
// And we are resetting to find the next component...
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index 3867d2d..b6e6991 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -2064,21 +2064,6 @@
}
}
- boolean reportResumedActivityLocked(ActivityRecord r) {
- // A resumed activity cannot be stopping. remove from list
- mStoppingActivities.remove(r);
-
- final Task rootTask = r.getRootTask();
- if (rootTask.getDisplayArea().allResumedActivitiesComplete()) {
- mRootWindowContainer.ensureActivitiesVisible();
- // Make sure activity & window visibility should be identical
- // for all displays in this stage.
- mRootWindowContainer.executeAppTransitionForAllDisplay();
- return true;
- }
- return false;
- }
-
// Called when WindowManager has finished animating the launchingBehind activity to the back.
private void handleLaunchTaskBehindCompleteLocked(ActivityRecord r) {
final Task task = r.getTask();
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index f5ab38f..54ba47e 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -1905,6 +1905,7 @@
// Don't do recursive work.
return;
}
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "RWC_ensureActivitiesVisible");
mTaskSupervisor.beginActivityVisibilityUpdate();
try {
// First the front root tasks. In case any are not fullscreen and are in front of home.
@@ -1914,6 +1915,7 @@
}
} finally {
mTaskSupervisor.endActivityVisibilityUpdate();
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
}
diff --git a/services/core/java/com/android/server/wm/SafeActivityOptions.java b/services/core/java/com/android/server/wm/SafeActivityOptions.java
index f2dc55f..b452131 100644
--- a/services/core/java/com/android/server/wm/SafeActivityOptions.java
+++ b/services/core/java/com/android/server/wm/SafeActivityOptions.java
@@ -140,7 +140,9 @@
}
private ActivityOptions cloneLaunchingOptions(ActivityOptions options) {
- return options == null ? null : ActivityOptions.makeBasic()
+ if (options == null) return null;
+
+ final ActivityOptions cloneOptions = ActivityOptions.makeBasic()
.setLaunchTaskDisplayArea(options.getLaunchTaskDisplayArea())
.setLaunchDisplayId(options.getLaunchDisplayId())
.setCallerDisplayId(options.getCallerDisplayId())
@@ -150,6 +152,8 @@
.setPendingIntentCreatorBackgroundActivityStartMode(
options.getPendingIntentCreatorBackgroundActivityStartMode())
.setRemoteTransition(options.getRemoteTransition());
+ cloneOptions.setLaunchWindowingMode(options.getLaunchWindowingMode());
+ return cloneOptions;
}
/**
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 787c5d6..c72087b 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -1994,6 +1994,12 @@
final boolean wasInMultiWindowMode = inMultiWindowMode();
final boolean wasInPictureInPicture = inPinnedWindowingMode();
super.onConfigurationChanged(newParentConfig);
+ if (mDisplayContent == null) {
+ // This should be initializing from Task.Builder. The onConfigurationChanged will be
+ // called again when this task is attached to hierarchy. Early return here because the
+ // following operations are no-op for a non-attached task.
+ return;
+ }
// Only need to update surface size here since the super method will handle updating
// surface position.
updateSurfaceSize(getSyncTransaction());
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 63ca469..bc45c70 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -2816,6 +2816,9 @@
final Rect parentBounds = parent.getBounds();
change.setEndRelOffset(bounds.left - parentBounds.left,
bounds.top - parentBounds.top);
+ if (Flags.activityEmbeddingOverlayPresentationFlag()) {
+ change.setEndParentSize(parentBounds.width(), parentBounds.height());
+ }
int endRotation = target.getWindowConfiguration().getRotation();
if (activityRecord != null) {
// TODO(b/227427984): Shell needs to aware letterbox.
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 70143ba..6dbd259 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -202,8 +202,7 @@
private int mLastLayer = 0;
private SurfaceControl mLastRelativeToLayer = null;
- // TODO(b/132320879): Remove this from WindowContainers except DisplayContent.
- private final Transaction mPendingTransaction;
+ private Transaction mPendingTransaction;
/**
* Windows that clients are waiting to have drawn.
@@ -358,7 +357,6 @@
WindowContainer(WindowManagerService wms) {
mWmService = wms;
mTransitionController = mWmService.mAtmService.getTransitionController();
- mPendingTransaction = wms.mTransactionFactory.get();
mSyncTransaction = wms.mTransactionFactory.get();
mSurfaceAnimator = new SurfaceAnimator(this, this::onAnimationFinished, wms);
mSurfaceFreezer = new SurfaceFreezer(this, wms);
@@ -580,6 +578,10 @@
@Override
public void onConfigurationChanged(Configuration newParentConfig) {
super.onConfigurationChanged(newParentConfig);
+ if (mParent == null) {
+ // Avoid unnecessary surface operation before attaching to a parent.
+ return;
+ }
updateSurfacePositionNonOrganized();
scheduleAnimation();
if (mOverlayHost != null) {
@@ -1074,8 +1076,9 @@
}
}
mDisplayContent = dc;
- if (dc != null && dc != this) {
+ if (dc != null && dc != this && mPendingTransaction != null) {
dc.getPendingTransaction().merge(mPendingTransaction);
+ mPendingTransaction = null;
}
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowContainer child = mChildren.get(i);
@@ -2922,14 +2925,17 @@
@Override
public Transaction getPendingTransaction() {
- final DisplayContent displayContent = getDisplayContent();
- if (displayContent != null && displayContent != this) {
- return displayContent.getPendingTransaction();
+ final WindowContainer<?> dc = mDisplayContent;
+ if (dc != null && dc.mPendingTransaction != null) {
+ return dc.mPendingTransaction;
}
// This WindowContainer has not attached to a display yet or this is a DisplayContent, so we
// let the caller to save the surface operations within the local mPendingTransaction.
// If this is not a DisplayContent, we will merge it to the pending transaction of its
// display once it attaches to it.
+ if (mPendingTransaction == null) {
+ mPendingTransaction = mWmService.mTransactionFactory.get();
+ }
return mPendingTransaction;
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index b814ccd..2b375e1 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2027,7 +2027,9 @@
// Otherwise, look at the package
final ApplicationInfo appInfo = mPmInternal.getApplicationInfo(
packageName, 0 /* flags */, SYSTEM_UID, UserHandle.getUserId(callingUid));
- if (appInfo == null || appInfo.uid != callingUid) {
+ if (appInfo == null
+ || !mPmInternal.isSameApp(
+ packageName, callingUid, UserHandle.getUserId(callingUid))) {
throw new SecurityException("Package " + packageName + " not in UID "
+ callingUid);
}
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 72109d34..022c6ce 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -609,6 +609,8 @@
int effects = TRANSACT_EFFECTS_NONE;
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Apply window transaction, syncId=%d", syncId);
mService.deferWindowLayout();
+ mService.mTaskSupervisor.beginDeferResume();
+ boolean deferResume = true;
mService.mTaskSupervisor.setDeferRootVisibilityUpdate(true /* deferUpdate */);
final boolean shouldDeferTransitionReady = transition != null && !t.isEmpty()
&& (transition.isCollecting() || Flags.alwaysDeferTransitionWhenApplyWct());
@@ -750,6 +752,8 @@
}
if ((effects & TRANSACT_EFFECTS_LIFECYCLE) != 0) {
mService.mTaskSupervisor.setDeferRootVisibilityUpdate(false /* deferUpdate */);
+ mService.mTaskSupervisor.endDeferResume();
+ deferResume = false;
// Already calls ensureActivityConfig
mService.mRootWindowContainer.ensureActivitiesVisible();
mService.mRootWindowContainer.resumeFocusedTasksTopActivities();
@@ -771,6 +775,9 @@
transition.continueTransitionReady();
}
mService.mTaskSupervisor.setDeferRootVisibilityUpdate(false /* deferUpdate */);
+ if (deferResume) {
+ mService.mTaskSupervisor.endDeferResume();
+ }
mService.continueWindowLayout();
}
return effects;
diff --git a/services/devicepolicy/Android.bp b/services/devicepolicy/Android.bp
index da965bb..32b571a 100644
--- a/services/devicepolicy/Android.bp
+++ b/services/devicepolicy/Android.bp
@@ -17,8 +17,10 @@
java_library_static {
name: "services.devicepolicy",
defaults: ["platform_service_defaults"],
- srcs: [":services.devicepolicy-sources"],
-
+ srcs: [
+ ":services.devicepolicy-sources",
+ ":statslog-devicepolicy-java-gen",
+ ],
libs: [
"services.core",
"app-compat-annotations",
@@ -27,3 +29,11 @@
"androidx.annotation_annotation",
],
}
+
+genrule {
+ name: "statslog-devicepolicy-java-gen",
+ tools: ["stats-log-api-gen"],
+ cmd: "$(location stats-log-api-gen) --java $(out) --module devicepolicy" +
+ " --javaPackage com.android.server.devicepolicy --javaClass DevicePolicyStatsLog",
+ out: ["com/android/server/devicepolicy/DevicePolicyStatsLog.java"],
+}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index e8204e0..e122fe0 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -109,6 +109,7 @@
import static android.app.AppOpsManager.OPSTR_SYSTEM_EXEMPT_FROM_SUSPENSION;
import static android.app.AppOpsManager.OP_RUN_ANY_IN_BACKGROUND;
import static android.app.AppOpsManager.OP_RUN_IN_BACKGROUND;
+import static android.app.StatsManager.PULL_SUCCESS;
import static android.app.admin.DeviceAdminInfo.HEADLESS_DEVICE_OWNER_MODE_AFFILIATED;
import static android.app.admin.DeviceAdminInfo.HEADLESS_DEVICE_OWNER_MODE_SINGLE_USER;
import static android.app.admin.DeviceAdminInfo.HEADLESS_DEVICE_OWNER_MODE_UNSUPPORTED;
@@ -265,12 +266,26 @@
import static android.security.keystore.AttestationUtils.USE_INDIVIDUAL_ATTESTATION;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_ENTRY_POINT_ADB;
+import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_ADAPTIVE_AUTH_REQUEST;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
import static com.android.server.SystemTimeZone.TIME_ZONE_CONFIDENCE_HIGH;
import static com.android.server.am.ActivityManagerService.STOCK_PM_FLAGS;
import static com.android.server.devicepolicy.DevicePolicyEngine.DEFAULT_POLICY_SIZE_LIMIT;
+import static com.android.server.devicepolicy.DevicePolicyStatsLog.DEVICE_POLICY_MANAGEMENT_MODE;
+import static com.android.server.devicepolicy.DevicePolicyStatsLog.DEVICE_POLICY_MANAGEMENT_MODE__MANAGEMENT_MODE__COPE;
+import static com.android.server.devicepolicy.DevicePolicyStatsLog.DEVICE_POLICY_MANAGEMENT_MODE__MANAGEMENT_MODE__DEVICE_OWNER;
+import static com.android.server.devicepolicy.DevicePolicyStatsLog.DEVICE_POLICY_MANAGEMENT_MODE__MANAGEMENT_MODE__DEVICE_OWNER_FINANCED;
+import static com.android.server.devicepolicy.DevicePolicyStatsLog.DEVICE_POLICY_MANAGEMENT_MODE__MANAGEMENT_MODE__MANAGEMENT_MODE_UNSPECIFIED;
+import static com.android.server.devicepolicy.DevicePolicyStatsLog.DEVICE_POLICY_MANAGEMENT_MODE__MANAGEMENT_MODE__PROFILE_OWNER;
+import static com.android.server.devicepolicy.DevicePolicyStatsLog.DEVICE_POLICY_STATE;
+import static com.android.server.devicepolicy.DevicePolicyStatsLog.DEVICE_POLICY_STATE__PASSWORD_COMPLEXITY__COMPLEXITY_HIGH;
+import static com.android.server.devicepolicy.DevicePolicyStatsLog.DEVICE_POLICY_STATE__PASSWORD_COMPLEXITY__COMPLEXITY_LEGACY;
+import static com.android.server.devicepolicy.DevicePolicyStatsLog.DEVICE_POLICY_STATE__PASSWORD_COMPLEXITY__COMPLEXITY_LOW;
+import static com.android.server.devicepolicy.DevicePolicyStatsLog.DEVICE_POLICY_STATE__PASSWORD_COMPLEXITY__COMPLEXITY_MEDIUM;
+import static com.android.server.devicepolicy.DevicePolicyStatsLog.DEVICE_POLICY_STATE__PASSWORD_COMPLEXITY__COMPLEXITY_NONE;
+import static com.android.server.devicepolicy.DevicePolicyStatsLog.DEVICE_POLICY_STATE__PASSWORD_COMPLEXITY__COMPLEXITY_UNSPECIFIED;
import static com.android.server.devicepolicy.TransferOwnershipMetadataManager.ADMIN_TYPE_DEVICE_OWNER;
import static com.android.server.devicepolicy.TransferOwnershipMetadataManager.ADMIN_TYPE_PROFILE_OWNER;
import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
@@ -305,6 +320,7 @@
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
+import android.app.StatsManager;
import android.app.StatusBarManager;
import android.app.admin.AccountTypePolicyKey;
import android.app.admin.BooleanPolicyValue;
@@ -477,6 +493,7 @@
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.StatsEvent;
import android.util.Xml;
import android.view.IWindowManager;
import android.view.accessibility.AccessibilityManager;
@@ -3348,6 +3365,9 @@
synchronized (getLockObject()) {
mDevicePolicyEngine.reapplyAllPoliciesOnBootLocked();
}
+ if (Flags.managementModePolicyMetrics()) {
+ registerStatsCallbacks();
+ }
break;
case SystemService.PHASE_ACTIVITY_MANAGER_READY:
synchronized (getLockObject()) {
@@ -3487,6 +3507,121 @@
return true;
}
+ /** Register callbacks for statsd pulled atoms. */
+ private void registerStatsCallbacks() {
+ final StatsManager statsManager = mContext.getSystemService(StatsManager.class);
+ if (statsManager == null) {
+ Slog.wtf(LOG_TAG, "StatsManager system service not found.");
+ return;
+ }
+ statsManager.setPullAtomCallback(
+ DEVICE_POLICY_MANAGEMENT_MODE,
+ null, // use defaultPullAtomMetadata values
+ DIRECT_EXECUTOR,
+ this::onPullManagementModeAtom);
+ statsManager.setPullAtomCallback(
+ DEVICE_POLICY_STATE,
+ null, // use defaultPullAtomMetadata values
+ DIRECT_EXECUTOR,
+ this::onPullPolicyStateAtom);
+ }
+
+ /** Writes the pulled atoms. */
+ private int onPullManagementModeAtom(int atomTag, List<StatsEvent> statsEvents) {
+ synchronized (getLockObject()) {
+ statsEvents.add(DevicePolicyStatsLog.buildStatsEvent(
+ DEVICE_POLICY_MANAGEMENT_MODE,
+ getStatsManagementModeLocked().managementMode()));
+ return PULL_SUCCESS;
+ }
+ }
+
+ /** Writes the pulled atoms. */
+ private int onPullPolicyStateAtom(int atomTag, List<StatsEvent> statsEvents) {
+ synchronized (getLockObject()) {
+ StatsManagementMode statsManagementMode = getStatsManagementModeLocked();
+ if (statsManagementMode.admin() != null) {
+ statsEvents.add(DevicePolicyStatsLog.buildStatsEvent(DEVICE_POLICY_STATE,
+ getRequiredPasswordComplexityStatsLocked(statsManagementMode.admin()),
+ statsManagementMode.managementMode()
+ ));
+ } else {
+ statsEvents.add(DevicePolicyStatsLog.buildStatsEvent(DEVICE_POLICY_STATE,
+ DEVICE_POLICY_STATE__PASSWORD_COMPLEXITY__COMPLEXITY_NONE,
+ DEVICE_POLICY_MANAGEMENT_MODE__MANAGEMENT_MODE__MANAGEMENT_MODE_UNSPECIFIED
+ ));
+ }
+ return PULL_SUCCESS;
+ }
+ }
+
+ private StatsManagementMode getStatsManagementModeLocked() {
+ int managementMode =
+ DEVICE_POLICY_MANAGEMENT_MODE__MANAGEMENT_MODE__MANAGEMENT_MODE_UNSPECIFIED;
+ ActiveAdmin admin = getDeviceOwnerAdminLocked();
+ if (admin != null) {
+ managementMode = getDeviceOwnerTypeLocked(
+ getDeviceOwnerComponent(false).getPackageName())
+ != DEVICE_OWNER_TYPE_FINANCED
+ ? DEVICE_POLICY_MANAGEMENT_MODE__MANAGEMENT_MODE__DEVICE_OWNER
+ : DEVICE_POLICY_MANAGEMENT_MODE__MANAGEMENT_MODE__DEVICE_OWNER_FINANCED;
+ } else {
+ // Find the first user with managing_app.
+ for (Integer profileUserId : mOwners.getProfileOwnerKeys()) {
+ if (isManagedProfile(profileUserId)) {
+ admin = getProfileOwnerAdminLocked(profileUserId);
+ managementMode = mOwners.isProfileOwnerOfOrganizationOwnedDevice(
+ profileUserId)
+ ? DEVICE_POLICY_MANAGEMENT_MODE__MANAGEMENT_MODE__COPE
+ : DEVICE_POLICY_MANAGEMENT_MODE__MANAGEMENT_MODE__PROFILE_OWNER;
+ break;
+ }
+ }
+ }
+ return new StatsManagementMode(managementMode, admin);
+ }
+
+ private record StatsManagementMode(int managementMode, ActiveAdmin admin) {
+ }
+
+ @GuardedBy("getLockObject()")
+ private int getRequiredPasswordComplexityStatsLocked(ActiveAdmin admin) {
+ int userId = admin.getUserHandle().getIdentifier();
+ EnforcingAdmin enforcingAdmin = EnforcingAdmin.createEnterpriseEnforcingAdmin(
+ admin.info.getComponent(),
+ userId,
+ admin);
+
+ Integer passwordComplexity = mDevicePolicyEngine.getLocalPolicySetByAdmin(
+ PolicyDefinition.PASSWORD_COMPLEXITY,
+ enforcingAdmin,
+ userId);
+ if (passwordComplexity == null) {
+ return admin.mPasswordPolicy.quality != PASSWORD_QUALITY_UNSPECIFIED
+ ? DEVICE_POLICY_STATE__PASSWORD_COMPLEXITY__COMPLEXITY_LEGACY
+ : DEVICE_POLICY_STATE__PASSWORD_COMPLEXITY__COMPLEXITY_UNSPECIFIED;
+ }
+ switch (passwordComplexity) {
+ case PASSWORD_COMPLEXITY_NONE -> {
+ return DEVICE_POLICY_STATE__PASSWORD_COMPLEXITY__COMPLEXITY_NONE;
+ }
+ case PASSWORD_COMPLEXITY_LOW -> {
+ return DEVICE_POLICY_STATE__PASSWORD_COMPLEXITY__COMPLEXITY_LOW;
+ }
+ case PASSWORD_COMPLEXITY_MEDIUM -> {
+ return DEVICE_POLICY_STATE__PASSWORD_COMPLEXITY__COMPLEXITY_MEDIUM;
+ }
+ case PASSWORD_COMPLEXITY_HIGH -> {
+ return DEVICE_POLICY_STATE__PASSWORD_COMPLEXITY__COMPLEXITY_HIGH;
+ }
+ default -> {
+ Slogf.wtf(LOG_TAG, "Unhandled password complexity: " + passwordComplexity);
+ // The following line is unreachable as Slogf.wtf crashes the process.
+ // But we need this to avoid compilation error missing return statement.
+ return DEVICE_POLICY_STATE__PASSWORD_COMPLEXITY__COMPLEXITY_UNSPECIFIED;
+ }
+ }
+ }
private void applyManagedSubscriptionsPolicyIfRequired() {
int copeProfileUserId = getOrganizationOwnedProfileUserId();
@@ -4115,6 +4250,10 @@
private void clearOrgOwnedProfileOwnerUserRestrictions(UserHandle parentUserHandle) {
mUserManager.setUserRestriction(
UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, false, parentUserHandle);
+ if (mInjector.userManagerIsHeadlessSystemUserMode()) {
+ mUserManager.setUserRestriction(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE,
+ false, UserHandle.SYSTEM);
+ }
mUserManager.setUserRestriction(
UserManager.DISALLOW_ADD_USER, false, parentUserHandle);
}
@@ -17874,6 +18013,12 @@
mUserManager.setUserRestriction(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE,
isProfileOwnerOnOrganizationOwnedDevice,
parentUser);
+ if (mInjector.userManagerIsHeadlessSystemUserMode()) {
+ // For HSUM, additionally set this on user 0 to block ADB from removing the profile.
+ mUserManager.setUserRestriction(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE,
+ isProfileOwnerOnOrganizationOwnedDevice,
+ UserHandle.SYSTEM);
+ }
mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_USER,
isProfileOwnerOnOrganizationOwnedDevice,
parentUser);
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 107c294..611a4eb 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1924,7 +1924,11 @@
startRotationResolverService(context, t);
startSystemCaptionsManagerService(context, t);
startTextToSpeechManagerService(context, t);
- startWearableSensingService(t);
+ if (!isWatch || !android.server.Flags.removeWearableSensingServiceFromWear()) {
+ startWearableSensingService(t);
+ } else {
+ Slog.d(TAG, "Not starting WearableSensingService");
+ }
startOnDeviceIntelligenceService(t);
if (deviceHasConfigString(
diff --git a/services/java/com/android/server/flags.aconfig b/services/java/com/android/server/flags.aconfig
index 38354e8..e8aa68c 100644
--- a/services/java/com/android/server/flags.aconfig
+++ b/services/java/com/android/server/flags.aconfig
@@ -14,4 +14,11 @@
namespace: "wear_frameworks"
description: "Remove TextServiceManagerService on Wear"
bug: "323720705"
+}
+
+flag {
+ name: "remove_wearable_sensing_service_from_wear"
+ namespace: "wear_frameworks"
+ description: "Remove WearableSensingManagerService on Wear"
+ bug: "340929916"
}
\ No newline at end of file
diff --git a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
index cd70ed2..977a8a0 100644
--- a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
+++ b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
@@ -50,6 +50,7 @@
import com.android.server.wm.ActivityMetricsLaunchObserverRegistry;
import com.android.server.wm.ActivityTaskManagerInternal;
+import java.util.Arrays;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
@@ -378,10 +379,15 @@
@Override
public void onCameraOpened(String cameraId, String packageId) {
Log.d(LOG_TAG, "Received camera open event from: " + packageId);
- // Skip face auth and Android System Intelligence, since they trigger way too
- // often.
- if (packageId.startsWith("client.pid")
- || packageId.equals("com.google.android.as")) {
+ // Skip face auth since it triggers way too often.
+ if (packageId.startsWith("client.pid")) {
+ return;
+ }
+ // Additional vendor specific list of apps to skip.
+ String[] cameraSkipPackages =
+ getContext().getResources().getStringArray(
+ R.array.config_profcollectOnCameraOpenedSkipPackages);
+ if (Arrays.asList(cameraSkipPackages).contains(packageId)) {
return;
}
// Sample for a fraction of camera events.
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/AggregatedPowerStatsTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/AggregatedPowerStatsTest.java
index 9975190..a4688cc 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/AggregatedPowerStatsTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/AggregatedPowerStatsTest.java
@@ -42,6 +42,7 @@
@SmallTest
public class AggregatedPowerStatsTest {
private static final int TEST_POWER_COMPONENT = 1077;
+ private static final int CUSTOM_POWER_COMPONENT = 1042;
private static final int APP_1 = 27;
private static final int APP_2 = 42;
private static final int COMPONENT_STATE_0 = 0;
@@ -63,6 +64,20 @@
AggregatedPowerStatsConfig.STATE_SCREEN,
AggregatedPowerStatsConfig.STATE_PROCESS_STATE);
+ mAggregatedPowerStatsConfig.trackCustomPowerComponents(
+ () -> new PowerStatsProcessor() {
+ @Override
+ void finish(PowerComponentAggregatedPowerStats stats,
+ long timestampMs) {
+ }
+ })
+ .trackDeviceStates(
+ AggregatedPowerStatsConfig.STATE_POWER,
+ AggregatedPowerStatsConfig.STATE_SCREEN)
+ .trackUidStates(
+ AggregatedPowerStatsConfig.STATE_POWER,
+ AggregatedPowerStatsConfig.STATE_SCREEN,
+ AggregatedPowerStatsConfig.STATE_PROCESS_STATE);
SparseArray<String> stateLabels = new SparseArray<>();
stateLabels.put(COMPONENT_STATE_1, "one");
mPowerComponentDescriptor = new PowerStats.Descriptor(TEST_POWER_COMPONENT, "fan", 2,
@@ -137,6 +152,13 @@
ps.uidStats.put(APP_2, new long[]{100, 200, 300});
stats.addPowerStats(ps, 5000);
+
+ PowerStats custom = new PowerStats(
+ new PowerStats.Descriptor(CUSTOM_POWER_COMPONENT, "cu570m", 1, null, 0, 2,
+ new PersistableBundle()));
+ custom.stats = new long[]{123};
+ custom.uidStats.put(APP_1, new long[]{500, 600});
+ stats.addPowerStats(custom, 6000);
return stats;
}
@@ -149,12 +171,12 @@
assertThat(descriptor.uidStatsArrayLength).isEqualTo(3);
assertThat(descriptor.extras.getString("speed")).isEqualTo("fast");
- assertThat(getDeviceStats(stats,
+ assertThat(getDeviceStats(stats, TEST_POWER_COMPONENT,
AggregatedPowerStatsConfig.POWER_STATE_BATTERY,
AggregatedPowerStatsConfig.SCREEN_STATE_ON))
.isEqualTo(new long[]{322, 987});
- assertThat(getDeviceStats(stats,
+ assertThat(getDeviceStats(stats, TEST_POWER_COMPONENT,
AggregatedPowerStatsConfig.POWER_STATE_BATTERY,
AggregatedPowerStatsConfig.SCREEN_STATE_OTHER))
.isEqualTo(new long[]{222, 0});
@@ -185,51 +207,79 @@
.isEqualTo(new long[]{4500});
assertThat(getUidDeviceStats(stats,
- APP_1,
+ TEST_POWER_COMPONENT, APP_1,
AggregatedPowerStatsConfig.POWER_STATE_BATTERY,
AggregatedPowerStatsConfig.SCREEN_STATE_ON,
BatteryConsumer.PROCESS_STATE_UNSPECIFIED))
.isEqualTo(new long[]{259, 0, 492});
assertThat(getUidDeviceStats(stats,
- APP_1,
+ TEST_POWER_COMPONENT, APP_1,
AggregatedPowerStatsConfig.POWER_STATE_BATTERY,
AggregatedPowerStatsConfig.SCREEN_STATE_ON,
BatteryConsumer.PROCESS_STATE_CACHED))
.isEqualTo(new long[]{129, 0, 446});
assertThat(getUidDeviceStats(stats,
- APP_1,
+ TEST_POWER_COMPONENT, APP_1,
AggregatedPowerStatsConfig.POWER_STATE_BATTERY,
AggregatedPowerStatsConfig.SCREEN_STATE_OTHER,
BatteryConsumer.PROCESS_STATE_CACHED))
.isEqualTo(new long[]{0, 0, 200});
assertThat(getUidDeviceStats(stats,
- APP_2,
+ TEST_POWER_COMPONENT, APP_2,
AggregatedPowerStatsConfig.POWER_STATE_BATTERY,
AggregatedPowerStatsConfig.SCREEN_STATE_ON,
BatteryConsumer.PROCESS_STATE_UNSPECIFIED))
.isEqualTo(new long[]{185, 209, 418});
assertThat(getUidDeviceStats(stats,
- APP_2,
+ TEST_POWER_COMPONENT, APP_2,
AggregatedPowerStatsConfig.POWER_STATE_BATTERY,
AggregatedPowerStatsConfig.SCREEN_STATE_ON,
BatteryConsumer.PROCESS_STATE_FOREGROUND))
.isEqualTo(new long[]{142, 204, 359});
assertThat(getUidDeviceStats(stats,
- APP_2,
+ TEST_POWER_COMPONENT, APP_2,
AggregatedPowerStatsConfig.POWER_STATE_BATTERY,
AggregatedPowerStatsConfig.SCREEN_STATE_OTHER,
BatteryConsumer.PROCESS_STATE_BACKGROUND))
.isEqualTo(new long[]{50, 100, 150});
+
+ descriptor = stats.getPowerComponentStats(CUSTOM_POWER_COMPONENT)
+ .getPowerStatsDescriptor();
+ assertThat(descriptor.powerComponentId).isEqualTo(CUSTOM_POWER_COMPONENT);
+ assertThat(descriptor.statsArrayLength).isEqualTo(1);
+ assertThat(descriptor.uidStatsArrayLength).isEqualTo(2);
+
+ assertThat(getDeviceStats(stats, CUSTOM_POWER_COMPONENT,
+ AggregatedPowerStatsConfig.POWER_STATE_BATTERY,
+ AggregatedPowerStatsConfig.SCREEN_STATE_ON))
+ .isEqualTo(new long[]{61});
+ assertThat(getDeviceStats(stats, CUSTOM_POWER_COMPONENT,
+ AggregatedPowerStatsConfig.POWER_STATE_BATTERY,
+ AggregatedPowerStatsConfig.SCREEN_STATE_OTHER))
+ .isEqualTo(new long[]{61});
+ assertThat(getUidDeviceStats(stats,
+ CUSTOM_POWER_COMPONENT, APP_1,
+ AggregatedPowerStatsConfig.POWER_STATE_BATTERY,
+ AggregatedPowerStatsConfig.SCREEN_STATE_ON,
+ BatteryConsumer.PROCESS_STATE_CACHED))
+ .isEqualTo(new long[]{250, 300});
+ assertThat(getUidDeviceStats(stats,
+ CUSTOM_POWER_COMPONENT, APP_1,
+ AggregatedPowerStatsConfig.POWER_STATE_BATTERY,
+ AggregatedPowerStatsConfig.SCREEN_STATE_OTHER,
+ BatteryConsumer.PROCESS_STATE_CACHED))
+ .isEqualTo(new long[]{250, 300});
}
- private static long[] getDeviceStats(AggregatedPowerStats stats, int... states) {
+ private static long[] getDeviceStats(AggregatedPowerStats stats, int powerComponentId,
+ int... states) {
PowerComponentAggregatedPowerStats powerComponentStats =
- stats.getPowerComponentStats(TEST_POWER_COMPONENT);
+ stats.getPowerComponentStats(powerComponentId);
long[] out = new long[powerComponentStats.getPowerStatsDescriptor().statsArrayLength];
powerComponentStats.getDeviceStats(out, states);
return out;
@@ -243,9 +293,10 @@
return out;
}
- private static long[] getUidDeviceStats(AggregatedPowerStats stats, int uid, int... states) {
+ private static long[] getUidDeviceStats(AggregatedPowerStats stats, int powerComponentId,
+ int uid, int... states) {
PowerComponentAggregatedPowerStats powerComponentStats =
- stats.getPowerComponentStats(TEST_POWER_COMPONENT);
+ stats.getPowerComponentStats(powerComponentId);
long[] out = new long[powerComponentStats.getPowerStatsDescriptor().uidStatsArrayLength];
powerComponentStats.getUidStats(out, uid, states);
return out;
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/CameraPowerStatsTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/CameraPowerStatsTest.java
index 36deb08..efbd1b7 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/CameraPowerStatsTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/CameraPowerStatsTest.java
@@ -30,8 +30,11 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;
+import android.hardware.power.stats.EnergyConsumerResult;
import android.hardware.power.stats.EnergyConsumerType;
import android.os.BatteryConsumer;
import android.os.BatteryStats;
@@ -116,8 +119,10 @@
@Test
public void energyConsumerModel() {
- when(mConsumedEnergyRetriever.getEnergyConsumerIds(EnergyConsumerType.CAMERA, null))
+ when(mConsumedEnergyRetriever
+ .getEnergyConsumerIds(eq((int) EnergyConsumerType.CAMERA), any()))
.thenReturn(new int[]{ENERGY_CONSUMER_ID});
+
CameraPowerStatsProcessor processor = new CameraPowerStatsProcessor(
mStatsRule.getPowerProfile(), mUidResolver);
@@ -131,8 +136,8 @@
collector.setEnabled(true);
// Establish a baseline
- when(mConsumedEnergyRetriever.getConsumedEnergyUws(new int[]{ENERGY_CONSUMER_ID}))
- .thenReturn(new long[]{uCtoUj(10000)});
+ when(mConsumedEnergyRetriever.getConsumedEnergy(new int[]{ENERGY_CONSUMER_ID}))
+ .thenReturn(createEnergyConsumerResults(ENERGY_CONSUMER_ID, 10000));
collector.collectAndDeliverStats();
processor.noteStateChange(stats, buildHistoryItem(0, true, APP_UID1));
@@ -144,15 +149,15 @@
processor.noteStateChange(stats, buildHistoryItem(6000, false, APP_UID1));
- when(mConsumedEnergyRetriever.getConsumedEnergyUws(new int[]{ENERGY_CONSUMER_ID}))
- .thenReturn(new long[]{uCtoUj(2_170_000)});
+ when(mConsumedEnergyRetriever.getConsumedEnergy(new int[]{ENERGY_CONSUMER_ID}))
+ .thenReturn(createEnergyConsumerResults(ENERGY_CONSUMER_ID, 2_170_000));
collector.collectAndDeliverStats();
processor.noteStateChange(stats, buildHistoryItem(7000, true, APP_UID2));
mStatsRule.setTime(11_000, 11_000);
- when(mConsumedEnergyRetriever.getConsumedEnergyUws(new int[]{ENERGY_CONSUMER_ID}))
- .thenReturn(new long[]{uCtoUj(3_610_000)});
+ when(mConsumedEnergyRetriever.getConsumedEnergy(new int[]{ENERGY_CONSUMER_ID}))
+ .thenReturn(createEnergyConsumerResults(ENERGY_CONSUMER_ID, 3_610_000));
collector.collectAndDeliverStats();
processor.finish(stats, 11_000);
@@ -264,7 +269,10 @@
return powerComponentStats;
}
- private static long uCtoUj(long uc) {
- return (long) (uc * (double) VOLTAGE_MV / 1000);
+ private EnergyConsumerResult[] createEnergyConsumerResults(int id, long energyUWs) {
+ EnergyConsumerResult result = new EnergyConsumerResult();
+ result.id = id;
+ result.energyUWs = (long) (energyUWs * (double) VOLTAGE_MV / 1000);
+ return new EnergyConsumerResult[]{result};
}
}
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/CustomEnergyConsumerPowerStatsTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/CustomEnergyConsumerPowerStatsTest.java
new file mode 100644
index 0000000..7bec13f6
--- /dev/null
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/CustomEnergyConsumerPowerStatsTest.java
@@ -0,0 +1,298 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.power.stats;
+
+import static android.os.BatteryConsumer.PROCESS_STATE_BACKGROUND;
+import static android.os.BatteryConsumer.PROCESS_STATE_CACHED;
+import static android.os.BatteryConsumer.PROCESS_STATE_FOREGROUND;
+import static android.os.BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE;
+
+import static com.android.server.power.stats.AggregatedPowerStatsConfig.POWER_STATE_BATTERY;
+import static com.android.server.power.stats.AggregatedPowerStatsConfig.POWER_STATE_OTHER;
+import static com.android.server.power.stats.AggregatedPowerStatsConfig.SCREEN_STATE_ON;
+import static com.android.server.power.stats.AggregatedPowerStatsConfig.SCREEN_STATE_OTHER;
+import static com.android.server.power.stats.AggregatedPowerStatsConfig.STATE_POWER;
+import static com.android.server.power.stats.AggregatedPowerStatsConfig.STATE_PROCESS_STATE;
+import static com.android.server.power.stats.AggregatedPowerStatsConfig.STATE_SCREEN;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.when;
+
+import android.hardware.power.stats.EnergyConsumerAttribution;
+import android.hardware.power.stats.EnergyConsumerResult;
+import android.hardware.power.stats.EnergyConsumerType;
+import android.os.Handler;
+import android.os.Process;
+import android.platform.test.ravenwood.RavenwoodRule;
+
+import com.android.internal.os.Clock;
+import com.android.internal.os.PowerStats;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
+import java.util.function.IntSupplier;
+
+public class CustomEnergyConsumerPowerStatsTest {
+ @Rule(order = 0)
+ public final RavenwoodRule mRavenwood = new RavenwoodRule.Builder()
+ .setProvideMainThread(true)
+ .build();
+
+ @Rule(order = 1)
+ public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule();
+
+ public static final int ENERGY_CONSUMER_ID1 = 77;
+ public static final int ENERGY_CONSUMER_ID2 = 88;
+ private static final int VOLTAGE_MV = 3500;
+ private static final double PRECISION = 0.00001;
+ private static final int APP_UID1 = Process.FIRST_APPLICATION_UID + 42;
+ private static final int APP_UID2 = Process.FIRST_APPLICATION_UID + 101;
+ private static final EnergyConsumerPowerStatsLayout POWER_STATS_LAYOUT =
+ new EnergyConsumerPowerStatsLayout();
+
+ @Mock
+ private PowerStatsCollector.ConsumedEnergyRetriever mConsumedEnergyRetriever;
+
+ private final PowerStatsUidResolver mPowerStatsUidResolver = new PowerStatsUidResolver();
+
+ private EnergyConsumerPowerStatsCollector.Injector mInjector =
+ new EnergyConsumerPowerStatsCollector.Injector() {
+ @Override
+ public Handler getHandler() {
+ return mStatsRule.getHandler();
+ }
+
+ @Override
+ public Clock getClock() {
+ return mStatsRule.getMockClock();
+ }
+
+ @Override
+ public PowerStatsUidResolver getUidResolver() {
+ return mPowerStatsUidResolver;
+ }
+
+ @Override
+ public long getPowerStatsCollectionThrottlePeriod(String powerComponentName) {
+ return 0;
+ }
+
+ @Override
+ public PowerStatsCollector.ConsumedEnergyRetriever getConsumedEnergyRetriever() {
+ return mConsumedEnergyRetriever;
+ }
+
+ @Override
+ public IntSupplier getVoltageSupplier() {
+ return () -> VOLTAGE_MV;
+ }
+ };
+
+
+ private CustomEnergyConsumerPowerStatsCollector mCollector;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ mCollector = new CustomEnergyConsumerPowerStatsCollector(mInjector);
+ mCollector.setEnabled(true);
+ }
+
+ @Test
+ public void collectStats() throws Exception {
+ // Establish a baseline
+ collectPowerStats(0, 10_000, 30_000,
+ createAttribution(APP_UID1, 10_000),
+ createAttribution(APP_UID2, 15_000));
+
+ List<PowerStats> results = collectPowerStats(12345, 45_000, 100_000,
+ createAttribution(APP_UID1, 24_000),
+ createAttribution(APP_UID2, 36_000));
+
+ assertThat(results).hasSize(2);
+ PowerStats ps1 = results.stream()
+ .filter(ps -> ps.descriptor.name.equals("FOO")).findAny().orElseThrow();
+ assertThat(ps1.durationMs).isEqualTo(12345);
+
+ // Energy (uWs) / (voltage (mV) / 1000) -> charge (uC)
+ assertThat(POWER_STATS_LAYOUT.getConsumedEnergy(ps1.stats, 0))
+ .isEqualTo(10000);
+ assertThat(ps1.uidStats.size()).isEqualTo(0);
+
+ PowerStats ps2 = results.stream()
+ .filter(ps -> ps.descriptor.name.equals("BAR")).findAny().orElseThrow();
+ assertThat(POWER_STATS_LAYOUT.getConsumedEnergy(ps2.stats, 0))
+ .isEqualTo(20000);
+ assertThat(ps2.uidStats.size()).isEqualTo(2);
+ assertThat(POWER_STATS_LAYOUT.getUidConsumedEnergy(ps2.uidStats.get(APP_UID1), 0))
+ .isEqualTo(14000);
+ assertThat(POWER_STATS_LAYOUT.getUidConsumedEnergy(ps2.uidStats.get(APP_UID2), 0))
+ .isEqualTo(21000);
+ }
+
+ @Test
+ public void processStats() throws Exception {
+ AggregatedPowerStats aggregatedPowerStats = createAggregatedPowerStats();
+ aggregatedPowerStats.setDeviceState(STATE_POWER, POWER_STATE_OTHER, 0);
+ aggregatedPowerStats.setDeviceState(STATE_SCREEN, SCREEN_STATE_ON, 0);
+ aggregatedPowerStats.setUidState(APP_UID1, STATE_PROCESS_STATE, PROCESS_STATE_FOREGROUND,
+ 0);
+ aggregatedPowerStats.setUidState(APP_UID2, STATE_PROCESS_STATE, PROCESS_STATE_CACHED, 0);
+
+ List<PowerStats> results = collectPowerStats(0, 10_000, 30_000,
+ createAttribution(APP_UID1, 10_000),
+ createAttribution(APP_UID2, 15_000));
+ for (PowerStats powerStats : results) {
+ aggregatedPowerStats.addPowerStats(powerStats, 0);
+ }
+
+ aggregatedPowerStats.setDeviceState(STATE_POWER, POWER_STATE_BATTERY, 10_000);
+ aggregatedPowerStats.setDeviceState(STATE_SCREEN, SCREEN_STATE_OTHER, 10_000);
+ aggregatedPowerStats.setUidState(APP_UID1, STATE_PROCESS_STATE, PROCESS_STATE_BACKGROUND,
+ 10_000);
+ aggregatedPowerStats.setUidState(APP_UID2, STATE_PROCESS_STATE,
+ PROCESS_STATE_FOREGROUND_SERVICE, 10_000);
+
+ results = collectPowerStats(12345, 45_000, 100_000,
+ createAttribution(APP_UID1, 24_000),
+ createAttribution(APP_UID2, 36_000));
+ for (PowerStats powerStats : results) {
+ aggregatedPowerStats.addPowerStats(powerStats, 40_000);
+ }
+
+ aggregatedPowerStats.finish(40_0000);
+
+ List<PowerComponentAggregatedPowerStats> powerComponentStats =
+ aggregatedPowerStats.getPowerComponentStats();
+
+ PowerComponentAggregatedPowerStats ps1 = powerComponentStats.stream()
+ .filter(ps -> ps.getPowerStatsDescriptor().name.equals("FOO")).findAny()
+ .orElseThrow();
+ PowerComponentAggregatedPowerStats ps2 = powerComponentStats.stream()
+ .filter(ps -> ps.getPowerStatsDescriptor().name.equals("BAR")).findAny()
+ .orElseThrow();
+
+ long[] deviceStats = new long[ps1.getPowerStatsDescriptor().statsArrayLength];
+ long[] uidStats = new long[ps1.getPowerStatsDescriptor().uidStatsArrayLength];
+
+ // Total estimated power = 10,000 uC = 0.00278 mAh
+ double expectedPower = 0.00278;
+ ps1.getDeviceStats(deviceStats, states(POWER_STATE_OTHER, SCREEN_STATE_ON));
+ assertThat(POWER_STATS_LAYOUT.getDevicePowerEstimate(deviceStats))
+ .isWithin(PRECISION).of(expectedPower * 0.25);
+
+ ps1.getDeviceStats(deviceStats, states(POWER_STATE_BATTERY, SCREEN_STATE_OTHER));
+ assertThat(POWER_STATS_LAYOUT.getDevicePowerEstimate(deviceStats))
+ .isWithin(PRECISION).of(expectedPower * 0.75);
+
+ // UID1: estimated power = 14,000 uC = 0.00388 mAh
+ expectedPower = 0.00388;
+ ps2.getUidStats(uidStats, APP_UID1,
+ states(POWER_STATE_OTHER, SCREEN_STATE_ON, PROCESS_STATE_FOREGROUND));
+ assertThat(POWER_STATS_LAYOUT.getUidPowerEstimate(uidStats))
+ .isWithin(PRECISION).of(expectedPower * 0.25);
+
+ ps2.getUidStats(uidStats, APP_UID1,
+ states(POWER_STATE_BATTERY, SCREEN_STATE_OTHER, PROCESS_STATE_BACKGROUND));
+ assertThat(POWER_STATS_LAYOUT.getUidPowerEstimate(uidStats))
+ .isWithin(PRECISION).of(expectedPower * 0.75);
+
+ // UID2: estimated power = 21,000 uC = 0.00583 mAh
+ expectedPower = 0.00583;
+ ps2.getUidStats(uidStats, APP_UID2,
+ states(POWER_STATE_OTHER, SCREEN_STATE_ON, PROCESS_STATE_CACHED));
+ assertThat(POWER_STATS_LAYOUT.getUidPowerEstimate(uidStats))
+ .isWithin(PRECISION).of(expectedPower * 0.25);
+
+ ps2.getUidStats(uidStats, APP_UID2,
+ states(POWER_STATE_BATTERY, SCREEN_STATE_OTHER, PROCESS_STATE_FOREGROUND_SERVICE));
+ assertThat(POWER_STATS_LAYOUT.getUidPowerEstimate(uidStats))
+ .isWithin(PRECISION).of(expectedPower * 0.75);
+ }
+
+ private List<PowerStats> collectPowerStats(long timestamp, int chargeUc1, int chargeUc2,
+ EnergyConsumerAttribution... attributions2) throws Exception {
+ when(mConsumedEnergyRetriever.getEnergyConsumerIds(EnergyConsumerType.OTHER))
+ .thenReturn(new int[]{ENERGY_CONSUMER_ID1, ENERGY_CONSUMER_ID2});
+ when(mConsumedEnergyRetriever.getEnergyConsumerName(ENERGY_CONSUMER_ID1))
+ .thenReturn("FOO");
+ when(mConsumedEnergyRetriever.getEnergyConsumerName(ENERGY_CONSUMER_ID2))
+ .thenReturn("BAR");
+ when(mConsumedEnergyRetriever.getConsumedEnergy(new int[]{ENERGY_CONSUMER_ID1}))
+ .thenReturn(createEnergyConsumerResults(ENERGY_CONSUMER_ID1, chargeUc1, null));
+ when(mConsumedEnergyRetriever.getConsumedEnergy(new int[]{ENERGY_CONSUMER_ID2}))
+ .thenReturn(
+ createEnergyConsumerResults(ENERGY_CONSUMER_ID2, chargeUc2, attributions2));
+
+ mStatsRule.setTime(timestamp, timestamp);
+ List<PowerStats> results = new ArrayList<>();
+ CountDownLatch latch = new CountDownLatch(2);
+ Consumer<PowerStats> consumer = powerStats -> {
+ results.add(powerStats);
+ latch.countDown();
+ };
+ mCollector.addConsumer(consumer);
+ mCollector.schedule();
+ assertThat(latch.await(5, TimeUnit.SECONDS)).isTrue();
+ mCollector.removeConsumer(consumer);
+ return results;
+ }
+
+ private static AggregatedPowerStats createAggregatedPowerStats() {
+ AggregatedPowerStatsConfig config = new AggregatedPowerStatsConfig();
+ config.trackCustomPowerComponents(CustomEnergyConsumerPowerStatsProcessor::new)
+ .trackDeviceStates(
+ STATE_POWER,
+ STATE_SCREEN)
+ .trackUidStates(
+ STATE_POWER,
+ STATE_SCREEN,
+ STATE_PROCESS_STATE);
+
+ return new AggregatedPowerStats(config);
+ }
+
+ private EnergyConsumerResult[] createEnergyConsumerResults(int id, long energyUws,
+ EnergyConsumerAttribution[] attributions) {
+ EnergyConsumerResult result = new EnergyConsumerResult();
+ result.id = id;
+ result.energyUWs = energyUws;
+ result.attribution = attributions;
+ return new EnergyConsumerResult[]{result};
+ }
+
+ private EnergyConsumerAttribution createAttribution(int uid, long energyUWs) {
+ EnergyConsumerAttribution attribution = new EnergyConsumerAttribution();
+ attribution.uid = uid;
+ attribution.energyUWs = energyUWs;
+ return attribution;
+ }
+
+ private int[] states(int... states) {
+ return states;
+ }
+}
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/GnssPowerStatsTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/GnssPowerStatsTest.java
index 8a391c6..774be89 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/GnssPowerStatsTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/GnssPowerStatsTest.java
@@ -30,8 +30,11 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;
+import android.hardware.power.stats.EnergyConsumerResult;
import android.hardware.power.stats.EnergyConsumerType;
import android.location.GnssSignalQuality;
import android.os.BatteryConsumer;
@@ -119,8 +122,10 @@
@Test
public void powerProfileModel() {
// ODPM unsupported
- when(mConsumedEnergyRetriever.getEnergyConsumerIds(EnergyConsumerType.GNSS, null))
+ when(mConsumedEnergyRetriever
+ .getEnergyConsumerIds(eq((int) EnergyConsumerType.GNSS), any()))
.thenReturn(new int[0]);
+
GnssPowerStatsProcessor processor = new GnssPowerStatsProcessor(
mStatsRule.getPowerProfile(), mUidResolver);
@@ -209,7 +214,8 @@
@Test
public void energyConsumerModel() {
- when(mConsumedEnergyRetriever.getEnergyConsumerIds(EnergyConsumerType.GNSS, null))
+ when(mConsumedEnergyRetriever
+ .getEnergyConsumerIds(eq((int) EnergyConsumerType.GNSS), any()))
.thenReturn(new int[]{ENERGY_CONSUMER_ID});
GnssPowerStatsProcessor processor = new GnssPowerStatsProcessor(
mStatsRule.getPowerProfile(), mUidResolver);
@@ -224,8 +230,8 @@
collector.setEnabled(true);
// Establish a baseline
- when(mConsumedEnergyRetriever.getConsumedEnergyUws(new int[]{ENERGY_CONSUMER_ID}))
- .thenReturn(new long[]{uCtoUj(10000)});
+ when(mConsumedEnergyRetriever.getConsumedEnergy(new int[]{ENERGY_CONSUMER_ID}))
+ .thenReturn(createEnergyConsumerResults(ENERGY_CONSUMER_ID, 10000));
collector.collectAndDeliverStats();
processor.noteStateChange(stats, buildHistoryItem(0, true, APP_UID1));
@@ -237,8 +243,8 @@
processor.noteStateChange(stats, buildHistoryItem(6000, false, APP_UID1));
- when(mConsumedEnergyRetriever.getConsumedEnergyUws(new int[]{ENERGY_CONSUMER_ID}))
- .thenReturn(new long[]{uCtoUj(2_170_000)});
+ when(mConsumedEnergyRetriever.getConsumedEnergy(new int[]{ENERGY_CONSUMER_ID}))
+ .thenReturn(createEnergyConsumerResults(ENERGY_CONSUMER_ID, 2_170_000));
collector.collectAndDeliverStats();
processor.noteStateChange(stats, buildHistoryItem(7000, true, APP_UID2));
@@ -247,8 +253,8 @@
processor.noteStateChange(stats, buildHistoryItem(8000,
GnssSignalQuality.GNSS_SIGNAL_QUALITY_POOR));
mStatsRule.setTime(11_000, 11_000);
- when(mConsumedEnergyRetriever.getConsumedEnergyUws(new int[]{ENERGY_CONSUMER_ID}))
- .thenReturn(new long[]{uCtoUj(3_610_000)});
+ when(mConsumedEnergyRetriever.getConsumedEnergy(new int[]{ENERGY_CONSUMER_ID}))
+ .thenReturn(createEnergyConsumerResults(ENERGY_CONSUMER_ID, 3_610_000));
collector.collectAndDeliverStats();
processor.finish(stats, 11_000);
@@ -369,7 +375,10 @@
return powerComponentStats;
}
- private static long uCtoUj(long uc) {
- return (long) (uc * (double) VOLTAGE_MV / 1000);
+ private EnergyConsumerResult[] createEnergyConsumerResults(int id, long energyUWs) {
+ EnergyConsumerResult result = new EnergyConsumerResult();
+ result.id = id;
+ result.energyUWs = (long) (energyUWs * (double) VOLTAGE_MV / 1000);
+ return new EnergyConsumerResult[]{result};
}
}
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsExporterTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsExporterTest.java
index 412fc88..32bfb2c 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsExporterTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsExporterTest.java
@@ -79,6 +79,8 @@
private BatteryStatsHistory mHistory;
private CpuPowerStatsLayout mCpuStatsArrayLayout;
private PowerStats.Descriptor mPowerStatsDescriptor;
+ private final EnergyConsumerPowerStatsLayout mEnergyConsumerPowerStatsLayout =
+ new EnergyConsumerPowerStatsLayout();
@Before
public void setup() throws IOException {
@@ -87,14 +89,24 @@
AggregatedPowerStatsConfig config = new AggregatedPowerStatsConfig();
config.trackPowerComponent(BatteryConsumer.POWER_COMPONENT_CPU)
- .trackDeviceStates(AggregatedPowerStatsConfig.STATE_POWER,
+ .trackDeviceStates(
+ AggregatedPowerStatsConfig.STATE_POWER,
AggregatedPowerStatsConfig.STATE_SCREEN)
- .trackUidStates(AggregatedPowerStatsConfig.STATE_POWER,
+ .trackUidStates(
+ AggregatedPowerStatsConfig.STATE_POWER,
AggregatedPowerStatsConfig.STATE_SCREEN,
AggregatedPowerStatsConfig.STATE_PROCESS_STATE)
.setProcessor(
new CpuPowerStatsProcessor(mStatsRule.getPowerProfile(),
mStatsRule.getCpuScalingPolicies()));
+ config.trackCustomPowerComponents(CustomEnergyConsumerPowerStatsProcessor::new)
+ .trackDeviceStates(
+ AggregatedPowerStatsConfig.STATE_POWER,
+ AggregatedPowerStatsConfig.STATE_SCREEN)
+ .trackUidStates(
+ AggregatedPowerStatsConfig.STATE_POWER,
+ AggregatedPowerStatsConfig.STATE_SCREEN,
+ AggregatedPowerStatsConfig.STATE_PROCESS_STATE);
mPowerStatsStore = new PowerStatsStore(storeDirectory, new TestHandler(), config);
mHistory = new BatteryStatsHistory(Parcel.obtain(), storeDirectory, 0, 10000,
@@ -120,15 +132,25 @@
@Test
public void breakdownByProcState_fullRange() throws Exception {
BatteryUsageStats.Builder builder = new BatteryUsageStats.Builder(
- new String[0], /* includePowerModels */ false,
+ new String[]{"cu570m"}, /* includePowerModels */ false,
/* includeProcessStateData */ true, /* powerThreshold */ 0);
exportAggregatedPowerStats(builder, 1000, 10000);
BatteryUsageStats actual = builder.build();
String message = "Actual BatteryUsageStats: " + actual;
- assertDevicePowerEstimate(message, actual, BatteryConsumer.POWER_COMPONENT_CPU, 7.51016);
- assertAllAppsPowerEstimate(message, actual, BatteryConsumer.POWER_COMPONENT_CPU, 7.51016);
+ assertAggregatedPowerEstimate(message, actual,
+ BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE,
+ BatteryConsumer.POWER_COMPONENT_CPU, 7.51016);
+ assertAggregatedPowerEstimate(message, actual,
+ BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS,
+ BatteryConsumer.POWER_COMPONENT_CPU, 7.51016);
+ assertAggregatedPowerEstimate(message, actual,
+ BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE,
+ BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, 3.60);
+ assertAggregatedPowerEstimate(message, actual,
+ BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS,
+ BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, 0.360);
assertUidPowerEstimate(message, actual, APP_UID1, BatteryConsumer.POWER_COMPONENT_CPU,
BatteryConsumer.PROCESS_STATE_ANY, 3.97099);
@@ -136,11 +158,17 @@
BatteryConsumer.PROCESS_STATE_FOREGROUND, 2.198082);
assertUidPowerEstimate(message, actual, APP_UID1, BatteryConsumer.POWER_COMPONENT_CPU,
BatteryConsumer.PROCESS_STATE_BACKGROUND, 1.772916);
+ assertUidPowerEstimate(message, actual, APP_UID1,
+ BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID,
+ BatteryConsumer.PROCESS_STATE_ANY, 0.360);
assertUidPowerEstimate(message, actual, APP_UID2, BatteryConsumer.POWER_COMPONENT_CPU,
BatteryConsumer.PROCESS_STATE_ANY, 3.538999);
assertUidPowerEstimate(message, actual, APP_UID2, BatteryConsumer.POWER_COMPONENT_CPU,
BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE, 3.538999);
+ assertUidPowerEstimate(message, actual, APP_UID2,
+ BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID,
+ BatteryConsumer.PROCESS_STATE_ANY, 0);
actual.close();
}
@@ -148,15 +176,19 @@
@Test
public void breakdownByProcState_subRange() throws Exception {
BatteryUsageStats.Builder builder = new BatteryUsageStats.Builder(
- new String[0], /* includePowerModels */ false,
+ new String[]{"cu570m"}, /* includePowerModels */ false,
/* includeProcessStateData */ true, /* powerThreshold */ 0);
exportAggregatedPowerStats(builder, 3700, 6700);
BatteryUsageStats actual = builder.build();
String message = "Actual BatteryUsageStats: " + actual;
- assertDevicePowerEstimate(message, actual, BatteryConsumer.POWER_COMPONENT_CPU, 4.526749);
- assertAllAppsPowerEstimate(message, actual, BatteryConsumer.POWER_COMPONENT_CPU, 4.526749);
+ assertAggregatedPowerEstimate(message, actual,
+ BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE,
+ BatteryConsumer.POWER_COMPONENT_CPU, 4.526749);
+ assertAggregatedPowerEstimate(message, actual,
+ BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS,
+ BatteryConsumer.POWER_COMPONENT_CPU, 4.526749);
assertUidPowerEstimate(message, actual, APP_UID1, BatteryConsumer.POWER_COMPONENT_CPU,
BatteryConsumer.PROCESS_STATE_ANY, 1.193332);
@@ -176,15 +208,19 @@
@Test
public void combinedProcessStates() throws Exception {
BatteryUsageStats.Builder builder = new BatteryUsageStats.Builder(
- new String[0], /* includePowerModels */ false,
+ new String[]{"cu570m"}, /* includePowerModels */ false,
/* includeProcessStateData */ false, /* powerThreshold */ 0);
exportAggregatedPowerStats(builder, 1000, 10000);
BatteryUsageStats actual = builder.build();
String message = "Actual BatteryUsageStats: " + actual;
- assertDevicePowerEstimate(message, actual, BatteryConsumer.POWER_COMPONENT_CPU, 7.51016);
- assertAllAppsPowerEstimate(message, actual, BatteryConsumer.POWER_COMPONENT_CPU, 7.51016);
+ assertAggregatedPowerEstimate(message, actual,
+ BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE,
+ BatteryConsumer.POWER_COMPONENT_CPU, 7.51016);
+ assertAggregatedPowerEstimate(message, actual,
+ BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS,
+ BatteryConsumer.POWER_COMPONENT_CPU, 7.51016);
assertUidPowerEstimate(message, actual, APP_UID1, BatteryConsumer.POWER_COMPONENT_CPU,
BatteryConsumer.PROCESS_STATE_ANY, 3.97099);
@@ -210,10 +246,19 @@
long[] uidStats2 = new long[mCpuStatsArrayLayout.getUidStatsArrayLength()];
powerStats.uidStats.put(APP_UID2, uidStats2);
+ PowerStats customPowerStats = new PowerStats(
+ new PowerStats.Descriptor(BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID,
+ "cu570m", mEnergyConsumerPowerStatsLayout.getDeviceStatsArrayLength(),
+ null, 0, mEnergyConsumerPowerStatsLayout.getUidStatsArrayLength(),
+ new PersistableBundle()));
+ long[] customUidStats = new long[mEnergyConsumerPowerStatsLayout.getUidStatsArrayLength()];
+ customPowerStats.uidStats.put(APP_UID1, customUidStats);
+
mHistory.forceRecordAllHistory();
mHistory.startRecordingHistory(1000, 1000, false);
mHistory.recordPowerStats(1000, 1000, powerStats);
+ mHistory.recordPowerStats(1000, 1000, customPowerStats);
mHistory.recordBatteryState(1000, 1000, 70, /* plugged */ false);
mHistory.recordStateStartEvent(1000, 1000, BatteryStats.HistoryItem.STATE_SCREEN_ON_FLAG);
mHistory.recordProcessStateChange(1000, 1000, APP_UID1,
@@ -245,6 +290,10 @@
mCpuStatsArrayLayout.setUidTimeByPowerBracket(uidStats2, 0, 40000);
mHistory.recordPowerStats(6000, 6000, powerStats);
+ mEnergyConsumerPowerStatsLayout.setConsumedEnergy(customPowerStats.stats, 0, 3_600_000);
+ mEnergyConsumerPowerStatsLayout.setUidConsumedEnergy(customUidStats, 0, 360_000);
+ mHistory.recordPowerStats(6010, 6010, customPowerStats);
+
mPowerStatsAggregator.aggregatePowerStats(3500, 6500, stats -> {
mPowerStatsStore.storeAggregatedPowerStats(stats);
});
@@ -271,20 +320,13 @@
exporter.exportAggregatedPowerStats(builder, monotonicStartTime, monotonicEndTime);
}
- private void assertDevicePowerEstimate(String message, BatteryUsageStats bus, int componentId,
- double expected) {
- AggregateBatteryConsumer consumer = bus.getAggregateBatteryConsumer(
- BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE);
- assertWithMessage(message).that(consumer.getConsumedPower(componentId))
- .isWithin(TOLERANCE).of(expected);
- }
-
- private void assertAllAppsPowerEstimate(String message, BatteryUsageStats bus, int componentId,
- double expected) {
- AggregateBatteryConsumer consumer = bus.getAggregateBatteryConsumer(
- BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS);
- assertWithMessage(message).that(consumer.getConsumedPower(componentId))
- .isWithin(TOLERANCE).of(expected);
+ private void assertAggregatedPowerEstimate(String message, BatteryUsageStats bus, int scope,
+ int componentId, double expected) {
+ AggregateBatteryConsumer consumer = bus.getAggregateBatteryConsumer(scope);
+ double actual = componentId < BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID
+ ? consumer.getConsumedPower(componentId)
+ : consumer.getConsumedPowerForCustomComponent(componentId);
+ assertWithMessage(message).that(actual).isWithin(TOLERANCE).of(expected);
}
private void assertUidPowerEstimate(String message, BatteryUsageStats bus, int uid,
@@ -293,9 +335,11 @@
final UidBatteryConsumer uidScope = uidScopes.stream()
.filter(us -> us.getUid() == uid).findFirst().orElse(null);
assertWithMessage(message).that(uidScope).isNotNull();
- assertWithMessage(message).that(uidScope.getConsumedPower(
- new BatteryConsumer.Dimensions(componentId, processState)))
- .isWithin(TOLERANCE).of(expected);
+ double actual = componentId < BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID
+ ? uidScope.getConsumedPower(
+ new BatteryConsumer.Dimensions(componentId, processState))
+ : uidScope.getConsumedPowerForCustomComponent(componentId);
+ assertWithMessage(message).that(actual).isWithin(TOLERANCE).of(expected);
}
private void clearDirectory(File dir) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index e91fd37..d143297 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -1639,6 +1639,15 @@
clearInvocations(mDefaultDisplay);
}
+ @Test
+ public void testCompleteResume_updateCompatDisplayInsets() {
+ final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build();
+ doReturn(true).when(activity).shouldCreateCompatDisplayInsets();
+ activity.setState(RESUMED, "test");
+ activity.completeResumeLocked();
+ assertNotNull(activity.getCompatDisplayInsets());
+ }
+
/**
* Verify destroy activity request completes successfully.
*/
diff --git a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
index a39a1a8..c67d1ec 100644
--- a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
@@ -550,7 +550,7 @@
}).when(appWindow.mSession).setOnBackInvokedCallbackInfo(eq(appWindow.mClient), any());
addToWindowMap(appWindow, true);
- dispatcher.attachToWindow(appWindow.mSession, appWindow.mClient, null);
+ dispatcher.attachToWindow(appWindow.mSession, appWindow.mClient, null, null);
OnBackInvokedCallback appCallback = createBackCallback(appLatch);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
index f94e5e3..35b6b70 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
@@ -499,8 +499,8 @@
.build();
final ActivityRecord activity0 = organizedTf.getBottomMostActivity();
final ActivityRecord activity1 = organizedTf.getTopMostActivity();
- // Bottom activity is untrusted embedding. Top activity is trusted embedded.
- // Activity0 has overlay over untrusted mode embedded.
+ // Bottom activity is untrusted embedding. Top activity is trusted embedded and occludes
+ // the bottom activity. Activity0 has overlay over untrusted mode embedded.
activity0.info.applicationInfo.uid = DEFAULT_TASK_FRAGMENT_ORGANIZER_UID + 1;
activity1.info.applicationInfo.uid = DEFAULT_TASK_FRAGMENT_ORGANIZER_UID;
doReturn(true).when(organizedTf).isAllowedToEmbedActivityInUntrustedMode(activity0);
@@ -537,6 +537,48 @@
}
@Test
+ public void testActivityHasOverlayOverUntrustedModeEmbeddedWithAdjacentTaskFragments() {
+ final Task rootTask = createTask(mDisplayContent, WINDOWING_MODE_MULTI_WINDOW,
+ ACTIVITY_TYPE_STANDARD);
+ final Rect taskBounds = rootTask.getBounds();
+ final TaskFragment organizedTf0 = new TaskFragmentBuilder(mAtm)
+ .createActivityCount(1)
+ .setParentTask(rootTask)
+ .setFragmentToken(new Binder())
+ .setOrganizer(mOrganizer)
+ .setBounds(new Rect(taskBounds.left, taskBounds.top,
+ taskBounds.left + taskBounds.width() / 2, taskBounds.bottom))
+ .build();
+ final TaskFragment organizedTf1 = new TaskFragmentBuilder(mAtm)
+ .createActivityCount(1)
+ .setParentTask(rootTask)
+ .setFragmentToken(new Binder())
+ .setOrganizer(mOrganizer)
+ .setBounds(new Rect(taskBounds.left + taskBounds.width() / 2, taskBounds.top,
+ taskBounds.right, taskBounds.bottom))
+ .build();
+ final ActivityRecord activity0 = organizedTf0.getTopMostActivity();
+ final ActivityRecord activity1 = organizedTf1.getTopMostActivity();
+
+ activity0.info.applicationInfo.uid = DEFAULT_TASK_FRAGMENT_ORGANIZER_UID + 1;
+ activity1.info.applicationInfo.uid = DEFAULT_TASK_FRAGMENT_ORGANIZER_UID;
+ doReturn(true).when(organizedTf0).isAllowedToEmbedActivityInUntrustedMode(activity0);
+
+ assertFalse("Activity0 doesn't have overlay because it's not occluded by activity1",
+ activity0.hasOverlayOverUntrustedModeEmbedded());
+ assertFalse(activity1.hasOverlayOverUntrustedModeEmbedded());
+
+ // Expand organizedTf1 bounds slightly.
+ final Rect tfBounds1 = organizedTf1.getBounds();
+ organizedTf1.setBounds(tfBounds1.left - 5, tfBounds1.top, taskBounds.right + 5,
+ tfBounds1.bottom);
+
+ assertTrue("Activity0 has overlay because it's occluded partially by activity1",
+ activity0.hasOverlayOverUntrustedModeEmbedded());
+ assertFalse(activity1.hasOverlayOverUntrustedModeEmbedded());
+ }
+
+ @Test
public void testIsAllowedToBeEmbeddedInTrustedMode() {
final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm)
.setCreateParentTask()
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
index 4ebbf49..a94b586 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
@@ -163,7 +163,7 @@
@Test
public void testAddChildSetsSurfacePosition() {
reset(mTransaction);
- try (MockSurfaceBuildingContainer top = new MockSurfaceBuildingContainer(mWm)) {
+ try (MockSurfaceBuildingContainer top = new MockSurfaceBuildingContainer(mDisplayContent)) {
WindowContainer child = new WindowContainer(mWm);
child.setBounds(1, 1, 10, 10);
@@ -266,7 +266,7 @@
@Test
public void testRemoveImmediatelyClearsLastSurfacePosition() {
reset(mTransaction);
- try (MockSurfaceBuildingContainer top = new MockSurfaceBuildingContainer(mWm)) {
+ try (MockSurfaceBuildingContainer top = new MockSurfaceBuildingContainer(mDisplayContent)) {
final WindowContainer<WindowContainer> child1 = new WindowContainer(mWm);
child1.setBounds(1, 1, 10, 10);
@@ -1827,8 +1827,9 @@
implements AutoCloseable {
private final SurfaceSession mSession = new SurfaceSession();
- MockSurfaceBuildingContainer(WindowManagerService wm) {
- super(wm);
+ MockSurfaceBuildingContainer(DisplayContent dc) {
+ super(dc.mWmService);
+ onDisplayChanged(dc);
}
static class MockSurfaceBuilder extends SurfaceControl.Builder {
diff --git a/packages/SystemUI/tests/utils/src/android/animation/AnimatorTestRule.java b/tests/testables/src/android/animation/AnimatorTestRule.java
similarity index 100%
rename from packages/SystemUI/tests/utils/src/android/animation/AnimatorTestRule.java
rename to tests/testables/src/android/animation/AnimatorTestRule.java
diff --git a/tests/testables/tests/Android.bp b/tests/testables/tests/Android.bp
index 06449e0..d6a4754 100644
--- a/tests/testables/tests/Android.bp
+++ b/tests/testables/tests/Android.bp
@@ -26,14 +26,18 @@
platform_apis: true,
srcs: [
"src/**/*.java",
+ "src/**/*.kt",
"src/**/I*.aidl",
],
resource_dirs: ["res"],
static_libs: [
+ "androidx.core_core-animation",
+ "androidx.core_core-ktx",
"androidx.test.rules",
"hamcrest-library",
"mockito-target-inline-minus-junit4",
"testables",
+ "truth",
],
compile_multilib: "both",
jni_libs: [
diff --git a/packages/SystemUI/tests/src/android/animation/AnimatorTestRuleIsolationTest.kt b/tests/testables/tests/src/android/animation/AnimatorTestRuleIsolationTest.kt
similarity index 94%
rename from packages/SystemUI/tests/src/android/animation/AnimatorTestRuleIsolationTest.kt
rename to tests/testables/tests/src/android/animation/AnimatorTestRuleIsolationTest.kt
index f23fbee..5abebee 100644
--- a/packages/SystemUI/tests/src/android/animation/AnimatorTestRuleIsolationTest.kt
+++ b/tests/testables/tests/src/android/animation/AnimatorTestRuleIsolationTest.kt
@@ -19,7 +19,6 @@
import android.testing.TestableLooper.RunWithLooper
import androidx.core.animation.doOnEnd
import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
import org.junit.Rule
import org.junit.Test
@@ -32,7 +31,7 @@
@RunWith(AndroidTestingRunner::class)
@SmallTest
@RunWithLooper
-class AnimatorTestRuleIsolationTest : SysuiTestCase() {
+class AnimatorTestRuleIsolationTest {
@get:Rule val animatorTestRule = AnimatorTestRule(this)
@@ -41,7 +40,7 @@
// GIVEN global state is reset at the start of the test
didTouchA = false
didTouchB = false
- // WHEN starting 2 animations of different durations, and setting didTouchA at the end
+ // WHEN starting 2 animations of different durations, and setting didTouch{A,B} at the end
ObjectAnimator.ofFloat(0f, 1f).apply {
duration = 100
doOnEnd { didTouchA = true }
@@ -49,7 +48,7 @@
}
ObjectAnimator.ofFloat(0f, 1f).apply {
duration = 150
- doOnEnd { didTouchA = true }
+ doOnEnd { didTouchB = true }
start()
}
// WHEN when you advance time so that only one of the animations has ended
@@ -65,7 +64,7 @@
// GIVEN global state is reset at the start of the test
didTouchA = false
didTouchB = false
- // WHEN starting 2 animations of different durations, and setting didTouchB at the end
+ // WHEN starting 2 animations of different durations, and setting didTouch{A,B} at the end
ObjectAnimator.ofFloat(0f, 1f).apply {
duration = 100
doOnEnd { didTouchB = true }
@@ -73,7 +72,7 @@
}
ObjectAnimator.ofFloat(0f, 1f).apply {
duration = 150
- doOnEnd { didTouchB = true }
+ doOnEnd { didTouchA = true }
start()
}
animatorTestRule.advanceTimeBy(100)
diff --git a/packages/SystemUI/tests/src/android/animation/AnimatorTestRulePrecisionTest.kt b/tests/testables/tests/src/android/animation/AnimatorTestRulePrecisionTest.kt
similarity index 96%
rename from packages/SystemUI/tests/src/android/animation/AnimatorTestRulePrecisionTest.kt
rename to tests/testables/tests/src/android/animation/AnimatorTestRulePrecisionTest.kt
index fd5f157..9eeaad5 100644
--- a/packages/SystemUI/tests/src/android/animation/AnimatorTestRulePrecisionTest.kt
+++ b/tests/testables/tests/src/android/animation/AnimatorTestRulePrecisionTest.kt
@@ -17,10 +17,9 @@
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
+import android.view.animation.LinearInterpolator
import androidx.core.animation.doOnEnd
import androidx.test.filters.SmallTest
-import com.android.app.animation.Interpolators
-import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
import org.junit.Rule
import org.junit.Test
@@ -29,7 +28,7 @@
@RunWith(AndroidTestingRunner::class)
@SmallTest
@RunWithLooper
-class AnimatorTestRulePrecisionTest : SysuiTestCase() {
+class AnimatorTestRulePrecisionTest {
@get:Rule val animatorTestRule = AnimatorTestRule(this)
@@ -43,7 +42,7 @@
crossinline onEndAction: (animator: Animator) -> Unit,
) {
ObjectAnimator.ofFloat(this, propertyName, 0f, 1f).also {
- it.interpolator = Interpolators.LINEAR
+ it.interpolator = LINEAR_INTERPOLATOR
it.duration = duration
it.startDelay = startDelay
it.doOnEnd(onEndAction)
@@ -190,4 +189,8 @@
assertThat(ended2).isTrue()
assertThat(AnimationHandler.getAnimationCount()).isEqualTo(0)
}
+
+ private companion object {
+ private val LINEAR_INTERPOLATOR = LinearInterpolator()
+ }
}