summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmds/incidentd/src/IncidentService.cpp20
-rw-r--r--core/java/android/app/IActivityTaskManager.aidl1
-rw-r--r--core/java/android/app/Instrumentation.java2
-rw-r--r--core/java/android/app/Notification.java61
-rw-r--r--core/java/android/app/NotificationManager.java6
-rw-r--r--core/java/android/app/UiAutomation.java2
-rw-r--r--core/java/android/content/pm/TEST_MAPPING28
-rw-r--r--core/java/android/database/DatabaseUtils.java32
-rw-r--r--core/java/android/hardware/usb/OWNERS4
-rw-r--r--core/java/android/hardware/usb/UsbConfiguration.java3
-rw-r--r--core/java/android/net/Uri.java36
-rw-r--r--core/java/android/os/PersistableBundle.java42
-rw-r--r--core/java/android/widget/RemoteViews.java15
-rw-r--r--core/jni/android_view_InputDevice.cpp11
-rw-r--r--core/tests/coretests/src/android/net/UriTest.java116
-rw-r--r--core/tests/coretests/src/android/widget/RemoteViewsTest.java53
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java21
-rw-r--r--libs/androidfw/CursorWindow.cpp10
-rw-r--r--libs/androidfw/include/androidfw/CursorWindow.h3
-rw-r--r--libs/androidfw/tests/CursorWindow_test.cpp31
-rw-r--r--media/java/android/media/RingtoneManager.java19
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java8
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java48
-rw-r--r--packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java25
-rw-r--r--packages/SystemUI/res/values-af/strings.xml1
-rw-r--r--packages/SystemUI/res/values-am/strings.xml1
-rw-r--r--packages/SystemUI/res/values-ar/strings.xml1
-rw-r--r--packages/SystemUI/res/values-as/strings.xml1
-rw-r--r--packages/SystemUI/res/values-az/strings.xml1
-rw-r--r--packages/SystemUI/res/values-b+sr+Latn/strings.xml1
-rw-r--r--packages/SystemUI/res/values-be/strings.xml1
-rw-r--r--packages/SystemUI/res/values-bg/strings.xml1
-rw-r--r--packages/SystemUI/res/values-bn/strings.xml1
-rw-r--r--packages/SystemUI/res/values-bs/strings.xml1
-rw-r--r--packages/SystemUI/res/values-ca/strings.xml1
-rw-r--r--packages/SystemUI/res/values-cs/strings.xml1
-rw-r--r--packages/SystemUI/res/values-da/strings.xml1
-rw-r--r--packages/SystemUI/res/values-de/strings.xml1
-rw-r--r--packages/SystemUI/res/values-el/strings.xml1
-rw-r--r--packages/SystemUI/res/values-en-rAU/strings.xml1
-rw-r--r--packages/SystemUI/res/values-en-rCA/strings.xml1
-rw-r--r--packages/SystemUI/res/values-en-rGB/strings.xml1
-rw-r--r--packages/SystemUI/res/values-en-rIN/strings.xml1
-rw-r--r--packages/SystemUI/res/values-en-rXC/strings.xml1
-rw-r--r--packages/SystemUI/res/values-es-rUS/strings.xml1
-rw-r--r--packages/SystemUI/res/values-es/strings.xml1
-rw-r--r--packages/SystemUI/res/values-et/strings.xml1
-rw-r--r--packages/SystemUI/res/values-eu/strings.xml1
-rw-r--r--packages/SystemUI/res/values-fa/strings.xml1
-rw-r--r--packages/SystemUI/res/values-fi/strings.xml1
-rw-r--r--packages/SystemUI/res/values-fr-rCA/strings.xml1
-rw-r--r--packages/SystemUI/res/values-fr/strings.xml1
-rw-r--r--packages/SystemUI/res/values-gl/strings.xml1
-rw-r--r--packages/SystemUI/res/values-gu/strings.xml1
-rw-r--r--packages/SystemUI/res/values-hi/strings.xml1
-rw-r--r--packages/SystemUI/res/values-hr/strings.xml1
-rw-r--r--packages/SystemUI/res/values-hu/strings.xml1
-rw-r--r--packages/SystemUI/res/values-hy/strings.xml1
-rw-r--r--packages/SystemUI/res/values-in/strings.xml1
-rw-r--r--packages/SystemUI/res/values-is/strings.xml1
-rw-r--r--packages/SystemUI/res/values-it/strings.xml1
-rw-r--r--packages/SystemUI/res/values-iw/strings.xml1
-rw-r--r--packages/SystemUI/res/values-ja/strings.xml1
-rw-r--r--packages/SystemUI/res/values-ka/strings.xml1
-rw-r--r--packages/SystemUI/res/values-kk/strings.xml1
-rw-r--r--packages/SystemUI/res/values-km/strings.xml1
-rw-r--r--packages/SystemUI/res/values-kn/strings.xml1
-rw-r--r--packages/SystemUI/res/values-ko/strings.xml1
-rw-r--r--packages/SystemUI/res/values-ky/strings.xml1
-rw-r--r--packages/SystemUI/res/values-lo/strings.xml1
-rw-r--r--packages/SystemUI/res/values-lt/strings.xml1
-rw-r--r--packages/SystemUI/res/values-lv/strings.xml1
-rw-r--r--packages/SystemUI/res/values-mk/strings.xml1
-rw-r--r--packages/SystemUI/res/values-ml/strings.xml1
-rw-r--r--packages/SystemUI/res/values-mn/strings.xml1
-rw-r--r--packages/SystemUI/res/values-mr/strings.xml1
-rw-r--r--packages/SystemUI/res/values-ms/strings.xml1
-rw-r--r--packages/SystemUI/res/values-my/strings.xml1
-rw-r--r--packages/SystemUI/res/values-nb/strings.xml1
-rw-r--r--packages/SystemUI/res/values-ne/strings.xml1
-rw-r--r--packages/SystemUI/res/values-nl/strings.xml1
-rw-r--r--packages/SystemUI/res/values-or/strings.xml1
-rw-r--r--packages/SystemUI/res/values-pa/strings.xml1
-rw-r--r--packages/SystemUI/res/values-pl/strings.xml1
-rw-r--r--packages/SystemUI/res/values-pt-rBR/strings.xml1
-rw-r--r--packages/SystemUI/res/values-pt-rPT/strings.xml1
-rw-r--r--packages/SystemUI/res/values-pt/strings.xml1
-rw-r--r--packages/SystemUI/res/values-ro/strings.xml1
-rw-r--r--packages/SystemUI/res/values-ru/strings.xml1
-rw-r--r--packages/SystemUI/res/values-si/strings.xml1
-rw-r--r--packages/SystemUI/res/values-sk/strings.xml1
-rw-r--r--packages/SystemUI/res/values-sl/strings.xml1
-rw-r--r--packages/SystemUI/res/values-sq/strings.xml1
-rw-r--r--packages/SystemUI/res/values-sr/strings.xml1
-rw-r--r--packages/SystemUI/res/values-sv/strings.xml1
-rw-r--r--packages/SystemUI/res/values-sw/strings.xml1
-rw-r--r--packages/SystemUI/res/values-ta/strings.xml1
-rw-r--r--packages/SystemUI/res/values-te/strings.xml1
-rw-r--r--packages/SystemUI/res/values-th/strings.xml1
-rw-r--r--packages/SystemUI/res/values-tl/strings.xml1
-rw-r--r--packages/SystemUI/res/values-tr/strings.xml1
-rw-r--r--packages/SystemUI/res/values-uk/strings.xml1
-rw-r--r--packages/SystemUI/res/values-ur/strings.xml1
-rw-r--r--packages/SystemUI/res/values-uz/strings.xml1
-rw-r--r--packages/SystemUI/res/values-vi/strings.xml1
-rw-r--r--packages/SystemUI/res/values-zh-rCN/strings.xml1
-rw-r--r--packages/SystemUI/res/values-zh-rHK/strings.xml1
-rw-r--r--packages/SystemUI/res/values-zh-rTW/strings.xml1
-rw-r--r--packages/SystemUI/res/values-zu/strings.xml1
-rw-r--r--packages/SystemUI/res/values/strings.xml2
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/management/StructureAdapter.kt11
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/CanUseIconPredicate.kt30
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt50
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/TemperatureControlBehavior.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/ThumbnailBehavior.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt46
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/ResumeMediaBrowser.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/ResumeMediaBrowserFactory.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java106
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/SmartActionsReceiver.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/events/StatusEvent.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java7
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/controls/ui/CanUseIconPredicateTest.kt81
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlViewHolderTest.kt3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt96
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaResumeListenerTest.kt74
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/ResumeMediaBrowserTest.kt8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/screenshot/SaveImageInBackgroundTaskTest.kt282
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java71
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java4
-rw-r--r--services/autofill/java/com/android/server/autofill/Helper.java43
-rw-r--r--services/autofill/java/com/android/server/autofill/ui/DialogFillUi.java12
-rw-r--r--services/autofill/java/com/android/server/autofill/ui/FillUi.java11
-rw-r--r--services/autofill/java/com/android/server/autofill/ui/SaveUi.java3
-rw-r--r--services/core/java/com/android/server/PendingIntentUtils.java1
-rw-r--r--services/core/java/com/android/server/accounts/AccountManagerService.java5
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java30
-rw-r--r--services/core/java/com/android/server/locksettings/LockSettingsService.java14
-rw-r--r--services/core/java/com/android/server/media/MediaSessionRecord.java53
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java7
-rw-r--r--services/core/java/com/android/server/pm/ShortcutPackage.java2
-rw-r--r--services/core/java/com/android/server/pm/ShortcutService.java26
-rw-r--r--services/core/java/com/android/server/pm/TEST_MAPPING6
-rw-r--r--services/core/java/com/android/server/vr/VrManagerService.java6
-rw-r--r--services/core/java/com/android/server/wm/ActivityStarter.java3
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java2
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java12
-rw-r--r--services/print/java/com/android/server/print/PrintManagerService.java35
-rw-r--r--services/tests/PackageManagerServiceTests/server/res/raw/install_app1_cert5bin12760 -> 12756 bytes
-rw-r--r--services/tests/PackageManagerServiceTests/server/res/raw/install_app1_cert5_rotated_cert6bin16856 -> 16852 bytes
-rw-r--r--services/tests/PackageManagerServiceTests/server/res/raw/install_app2_cert5_rotated_cert6bin16856 -> 16852 bytes
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/PackageManagerTests.java13
-rwxr-xr-xservices/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java95
-rw-r--r--services/usb/OWNERS4
-rw-r--r--telecomm/java/android/telecom/ParcelableConference.java12
-rw-r--r--telecomm/java/android/telecom/StatusHints.java53
167 files changed, 1802 insertions, 330 deletions
diff --git a/cmds/incidentd/src/IncidentService.cpp b/cmds/incidentd/src/IncidentService.cpp
index fbb99d2aea89..8e461afd9db0 100644
--- a/cmds/incidentd/src/IncidentService.cpp
+++ b/cmds/incidentd/src/IncidentService.cpp
@@ -500,9 +500,13 @@ status_t IncidentService::onTransact(uint32_t code, const Parcel& data, Parcel*
switch (code) {
case SHELL_COMMAND_TRANSACTION: {
- int in = data.readFileDescriptor();
- int out = data.readFileDescriptor();
- int err = data.readFileDescriptor();
+ unique_fd in, out, err;
+ if (status_t status = data.readUniqueFileDescriptor(&in); status != OK) return status;
+
+ if (status_t status = data.readUniqueFileDescriptor(&out); status != OK) return status;
+
+ if (status_t status = data.readUniqueFileDescriptor(&err); status != OK) return status;
+
int argc = data.readInt32();
Vector<String8> args;
for (int i = 0; i < argc && data.dataAvail() > 0; i++) {
@@ -512,15 +516,15 @@ status_t IncidentService::onTransact(uint32_t code, const Parcel& data, Parcel*
sp<IResultReceiver> resultReceiver =
IResultReceiver::asInterface(data.readStrongBinder());
- FILE* fin = fdopen(in, "r");
- FILE* fout = fdopen(out, "w");
- FILE* ferr = fdopen(err, "w");
+ FILE* fin = fdopen(in.release(), "r");
+ FILE* fout = fdopen(out.release(), "w");
+ FILE* ferr = fdopen(err.release(), "w");
if (fin == NULL || fout == NULL || ferr == NULL) {
resultReceiver->send(NO_MEMORY);
} else {
- err = command(fin, fout, ferr, args);
- resultReceiver->send(err);
+ status_t result = command(fin, fout, ferr, args);
+ resultReceiver->send(result);
}
if (fin != NULL) {
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index fe75dd302beb..b709b7ee90c3 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -239,6 +239,7 @@ interface IActivityTaskManager {
* {@link android.view.WindowManagerPolicyConstants#KEYGUARD_GOING_AWAY_FLAG_TO_SHADE}
* etc.
*/
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.CONTROL_KEYGUARD)")
void keyguardGoingAway(int flags);
void suppressResizeConfigChanges(boolean suppress);
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index 8984c4292023..da5f308a9958 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -91,7 +91,7 @@ public class Instrumentation {
private static final String TAG = "Instrumentation";
- private static final long CONNECT_TIMEOUT_MILLIS = 5000;
+ private static final long CONNECT_TIMEOUT_MILLIS = 60000;
/**
* @hide
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index e564ec149037..aff21ef9c5b8 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -2138,6 +2138,10 @@ public class Notification implements Parcelable
}
}
+ private void visitUris(@NonNull Consumer<Uri> visitor) {
+ visitIconUri(visitor, getIcon());
+ }
+
@Override
public Action clone() {
return new Action(
@@ -2823,7 +2827,7 @@ public class Notification implements Parcelable
if (actions != null) {
for (Action action : actions) {
- visitIconUri(visitor, action.getIcon());
+ action.visitUris(visitor);
}
}
@@ -2846,20 +2850,17 @@ public class Notification implements Parcelable
visitor.accept(Uri.parse(extras.getString(EXTRA_BACKGROUND_IMAGE_URI)));
}
- ArrayList<Person> people = extras.getParcelableArrayList(EXTRA_PEOPLE_LIST);
+ ArrayList<Person> people = extras.getParcelableArrayList(EXTRA_PEOPLE_LIST,
+ Person.class);
if (people != null && !people.isEmpty()) {
for (Person p : people) {
visitor.accept(p.getIconUri());
}
}
- final Person person = extras.getParcelable(EXTRA_MESSAGING_PERSON, Person.class);
- if (person != null) {
- visitor.accept(person.getIconUri());
- }
-
- final RemoteInputHistoryItem[] history = (RemoteInputHistoryItem[])
- extras.getParcelableArray(Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS);
+ final RemoteInputHistoryItem[] history = extras.getParcelableArray(
+ Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS,
+ RemoteInputHistoryItem.class);
if (history != null) {
for (int i = 0; i < history.length; i++) {
RemoteInputHistoryItem item = history[i];
@@ -2868,10 +2869,16 @@ public class Notification implements Parcelable
}
}
}
- }
- if (isStyle(MessagingStyle.class) && extras != null) {
- final Parcelable[] messages = extras.getParcelableArray(EXTRA_MESSAGES);
+ // Extras for MessagingStyle. We visit them even if not isStyle(MessagingStyle), since
+ // Notification Listeners might use directly (without the isStyle check).
+ final Person person = extras.getParcelable(EXTRA_MESSAGING_PERSON, Person.class);
+ if (person != null) {
+ visitor.accept(person.getIconUri());
+ }
+
+ final Parcelable[] messages = extras.getParcelableArray(EXTRA_MESSAGES,
+ Parcelable.class);
if (!ArrayUtils.isEmpty(messages)) {
for (MessagingStyle.Message message : MessagingStyle.Message
.getMessagesFromBundleArray(messages)) {
@@ -2884,7 +2891,8 @@ public class Notification implements Parcelable
}
}
- final Parcelable[] historic = extras.getParcelableArray(EXTRA_HISTORIC_MESSAGES);
+ final Parcelable[] historic = extras.getParcelableArray(EXTRA_HISTORIC_MESSAGES,
+ Parcelable.class);
if (!ArrayUtils.isEmpty(historic)) {
for (MessagingStyle.Message message : MessagingStyle.Message
.getMessagesFromBundleArray(historic)) {
@@ -2897,20 +2905,24 @@ public class Notification implements Parcelable
}
}
- visitIconUri(visitor, extras.getParcelable(EXTRA_CONVERSATION_ICON));
- }
+ visitIconUri(visitor, extras.getParcelable(EXTRA_CONVERSATION_ICON, Icon.class));
- if (isStyle(CallStyle.class) & extras != null) {
- Person callPerson = extras.getParcelable(EXTRA_CALL_PERSON);
+ // Extras for CallStyle (same reason for visiting without checking isStyle).
+ Person callPerson = extras.getParcelable(EXTRA_CALL_PERSON, Person.class);
if (callPerson != null) {
visitor.accept(callPerson.getIconUri());
}
- visitIconUri(visitor, extras.getParcelable(EXTRA_VERIFICATION_ICON));
+ visitIconUri(visitor, extras.getParcelable(EXTRA_VERIFICATION_ICON, Icon.class));
}
if (mBubbleMetadata != null) {
visitIconUri(visitor, mBubbleMetadata.getIcon());
}
+
+ if (extras != null && extras.containsKey(WearableExtender.EXTRA_WEARABLE_EXTENSIONS)) {
+ WearableExtender extender = new WearableExtender(this);
+ extender.visitUris(visitor);
+ }
}
/**
@@ -3403,8 +3415,11 @@ public class Notification implements Parcelable
*
* @hide
*/
- public void setAllowlistToken(@Nullable IBinder token) {
- mAllowlistToken = token;
+ public void clearAllowlistToken() {
+ mAllowlistToken = null;
+ if (publicVersion != null) {
+ publicVersion.clearAllowlistToken();
+ }
}
/**
@@ -11593,6 +11608,12 @@ public class Notification implements Parcelable
mFlags &= ~mask;
}
}
+
+ private void visitUris(@NonNull Consumer<Uri> visitor) {
+ for (Action action : mActions) {
+ action.visitUris(visitor);
+ }
+ }
}
/**
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index f6d27ad08b00..e129edf72849 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -562,6 +562,12 @@ public class NotificationManager {
*/
public static final int BUBBLE_PREFERENCE_SELECTED = 2;
+ /**
+ * Maximum length of the component name of a registered NotificationListenerService.
+ * @hide
+ */
+ public static int MAX_SERVICE_COMPONENT_NAME_LENGTH = 500;
+
@UnsupportedAppUsage
private static INotificationManager sService;
diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java
index ac6759396c8f..9568f68fb99c 100644
--- a/core/java/android/app/UiAutomation.java
+++ b/core/java/android/app/UiAutomation.java
@@ -113,7 +113,7 @@ public final class UiAutomation {
private static final int CONNECTION_ID_UNDEFINED = -1;
- private static final long CONNECT_TIMEOUT_MILLIS = 5000;
+ private static final long CONNECT_TIMEOUT_MILLIS = 60000;
/** Rotation constant: Unfreeze rotation (rotating the device changes its rotation state). */
public static final int ROTATION_UNFREEZE = -2;
diff --git a/core/java/android/content/pm/TEST_MAPPING b/core/java/android/content/pm/TEST_MAPPING
index 1c1f58a19abc..187a21e45331 100644
--- a/core/java/android/content/pm/TEST_MAPPING
+++ b/core/java/android/content/pm/TEST_MAPPING
@@ -53,20 +53,6 @@
],
"presubmit-large": [
{
- "name": "CtsContentTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "include-filter": "android.content.pm.cts"
- }
- ]
- },
- {
"name": "CtsUsesNativeLibraryTest",
"options": [
{
@@ -152,6 +138,20 @@
],
"postsubmit": [
{
+ "name": "CtsContentTestCases",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation": "org.junit.Ignore"
+ },
+ {
+ "include-filter": "android.content.pm.cts"
+ }
+ ]
+ },
+ {
"name": "CtsAppSecurityHostTestCases",
"options": [
{
diff --git a/core/java/android/database/DatabaseUtils.java b/core/java/android/database/DatabaseUtils.java
index 6c8a8500e4e3..d41df4f49d48 100644
--- a/core/java/android/database/DatabaseUtils.java
+++ b/core/java/android/database/DatabaseUtils.java
@@ -511,17 +511,31 @@ public class DatabaseUtils {
*/
public static void appendEscapedSQLString(StringBuilder sb, String sqlString) {
sb.append('\'');
- if (sqlString.indexOf('\'') != -1) {
- int length = sqlString.length();
- for (int i = 0; i < length; i++) {
- char c = sqlString.charAt(i);
- if (c == '\'') {
- sb.append('\'');
+ int length = sqlString.length();
+ for (int i = 0; i < length; i++) {
+ char c = sqlString.charAt(i);
+ if (Character.isHighSurrogate(c)) {
+ if (i == length - 1) {
+ continue;
+ }
+ if (Character.isLowSurrogate(sqlString.charAt(i + 1))) {
+ // add them both
+ sb.append(c);
+ sb.append(sqlString.charAt(i + 1));
+ continue;
+ } else {
+ // this is a lone surrogate, skip it
+ continue;
}
- sb.append(c);
}
- } else
- sb.append(sqlString);
+ if (Character.isLowSurrogate(c)) {
+ continue;
+ }
+ if (c == '\'') {
+ sb.append('\'');
+ }
+ sb.append(c);
+ }
sb.append('\'');
}
diff --git a/core/java/android/hardware/usb/OWNERS b/core/java/android/hardware/usb/OWNERS
index 8f5c2a025672..a753f9634d0d 100644
--- a/core/java/android/hardware/usb/OWNERS
+++ b/core/java/android/hardware/usb/OWNERS
@@ -1,3 +1,7 @@
# Bug component: 175220
+aprasath@google.com
+kumarashishg@google.com
+sarup@google.com
+anothermark@google.com
badhri@google.com
diff --git a/core/java/android/hardware/usb/UsbConfiguration.java b/core/java/android/hardware/usb/UsbConfiguration.java
index 66269cb772f8..b25f47b11532 100644
--- a/core/java/android/hardware/usb/UsbConfiguration.java
+++ b/core/java/android/hardware/usb/UsbConfiguration.java
@@ -172,7 +172,8 @@ public class UsbConfiguration implements Parcelable {
String name = in.readString();
int attributes = in.readInt();
int maxPower = in.readInt();
- Parcelable[] interfaces = in.readParcelableArray(UsbInterface.class.getClassLoader());
+ Parcelable[] interfaces = in.readParcelableArray(
+ UsbInterface.class.getClassLoader(), UsbInterface.class);
UsbConfiguration configuration = new UsbConfiguration(id, name, attributes, maxPower);
configuration.setInterfaces(interfaces);
return configuration;
diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java
index 3da696ad0bc7..7fbaf1027af6 100644
--- a/core/java/android/net/Uri.java
+++ b/core/java/android/net/Uri.java
@@ -882,10 +882,11 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
}
static Uri readFrom(Parcel parcel) {
+ final StringUri stringUri = new StringUri(parcel.readString8());
return new OpaqueUri(
- parcel.readString8(),
- Part.readFrom(parcel),
- Part.readFrom(parcel)
+ stringUri.parseScheme(),
+ stringUri.getSsp(),
+ stringUri.getFragmentPart()
);
}
@@ -895,9 +896,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeInt(TYPE_ID);
- parcel.writeString8(scheme);
- ssp.writeTo(parcel);
- fragment.writeTo(parcel);
+ parcel.writeString8(toString());
}
public boolean isHierarchical() {
@@ -1196,22 +1195,25 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
Part query, Part fragment) {
this.scheme = scheme;
this.authority = Part.nonNull(authority);
- this.path = path == null ? PathPart.NULL : path;
+ this.path = generatePath(path);
this.query = Part.nonNull(query);
this.fragment = Part.nonNull(fragment);
}
- static Uri readFrom(Parcel parcel) {
- final String scheme = parcel.readString8();
- final Part authority = Part.readFrom(parcel);
+ private PathPart generatePath(PathPart originalPath) {
// In RFC3986 the path should be determined based on whether there is a scheme or
// authority present (https://www.rfc-editor.org/rfc/rfc3986.html#section-3.3).
final boolean hasSchemeOrAuthority =
(scheme != null && scheme.length() > 0) || !authority.isEmpty();
- final PathPart path = PathPart.readFrom(hasSchemeOrAuthority, parcel);
- final Part query = Part.readFrom(parcel);
- final Part fragment = Part.readFrom(parcel);
- return new HierarchicalUri(scheme, authority, path, query, fragment);
+ final PathPart newPath = hasSchemeOrAuthority ? PathPart.makeAbsolute(originalPath)
+ : originalPath;
+ return newPath == null ? PathPart.NULL : newPath;
+ }
+
+ static Uri readFrom(Parcel parcel) {
+ final StringUri stringUri = new StringUri(parcel.readString8());
+ return new HierarchicalUri(stringUri.getScheme(), stringUri.getAuthorityPart(),
+ stringUri.getPathPart(), stringUri.getQueryPart(), stringUri.getFragmentPart());
}
public int describeContents() {
@@ -1220,11 +1222,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeInt(TYPE_ID);
- parcel.writeString8(scheme);
- authority.writeTo(parcel);
- path.writeTo(parcel);
- query.writeTo(parcel);
- fragment.writeTo(parcel);
+ parcel.writeString8(toString());
}
public boolean isHierarchical() {
diff --git a/core/java/android/os/PersistableBundle.java b/core/java/android/os/PersistableBundle.java
index f4edcb1317f4..acfd15cb005e 100644
--- a/core/java/android/os/PersistableBundle.java
+++ b/core/java/android/os/PersistableBundle.java
@@ -21,6 +21,7 @@ import static java.nio.charset.StandardCharsets.UTF_8;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.util.ArrayMap;
+import android.util.Slog;
import android.util.TypedXmlPullParser;
import android.util.TypedXmlSerializer;
import android.util.Xml;
@@ -50,6 +51,8 @@ import java.util.ArrayList;
*/
public final class PersistableBundle extends BaseBundle implements Cloneable, Parcelable,
XmlUtils.WriteMapCallback {
+ private static final String TAG = "PersistableBundle";
+
private static final String TAG_PERSISTABLEMAP = "pbundle_as_map";
/** An unmodifiable {@code PersistableBundle} that is always {@link #isEmpty() empty}. */
@@ -118,7 +121,11 @@ public final class PersistableBundle extends BaseBundle implements Cloneable, Pa
* @hide
*/
public PersistableBundle(Bundle b) {
- this(b.getItemwiseMap());
+ this(b, true);
+ }
+
+ private PersistableBundle(Bundle b, boolean throwException) {
+ this(b.getItemwiseMap(), throwException);
}
/**
@@ -127,7 +134,7 @@ public final class PersistableBundle extends BaseBundle implements Cloneable, Pa
* @param map a Map containing only those items that can be persisted.
* @throws IllegalArgumentException if any element of #map cannot be persisted.
*/
- private PersistableBundle(ArrayMap<String, Object> map) {
+ private PersistableBundle(ArrayMap<String, Object> map, boolean throwException) {
super();
mFlags = FLAG_DEFUSABLE;
@@ -136,16 +143,23 @@ public final class PersistableBundle extends BaseBundle implements Cloneable, Pa
// Now verify each item throwing an exception if there is a violation.
final int N = mMap.size();
- for (int i=0; i<N; i++) {
+ for (int i = N - 1; i >= 0; --i) {
Object value = mMap.valueAt(i);
if (value instanceof ArrayMap) {
// Fix up any Maps by replacing them with PersistableBundles.
- mMap.setValueAt(i, new PersistableBundle((ArrayMap<String, Object>) value));
+ mMap.setValueAt(i,
+ new PersistableBundle((ArrayMap<String, Object>) value, throwException));
} else if (value instanceof Bundle) {
- mMap.setValueAt(i, new PersistableBundle(((Bundle) value)));
+ mMap.setValueAt(i, new PersistableBundle((Bundle) value, throwException));
} else if (!isValidType(value)) {
- throw new IllegalArgumentException("Bad value in PersistableBundle key="
- + mMap.keyAt(i) + " value=" + value);
+ final String errorMsg = "Bad value in PersistableBundle key="
+ + mMap.keyAt(i) + " value=" + value;
+ if (throwException) {
+ throw new IllegalArgumentException(errorMsg);
+ } else {
+ Slog.wtfStack(TAG, errorMsg);
+ mMap.removeAt(i);
+ }
}
}
}
@@ -268,6 +282,15 @@ public final class PersistableBundle extends BaseBundle implements Cloneable, Pa
/** @hide */
public void saveToXml(TypedXmlSerializer out) throws IOException, XmlPullParserException {
unparcel();
+ // Explicitly drop invalid types an attacker may have added before persisting.
+ for (int i = mMap.size() - 1; i >= 0; --i) {
+ final Object value = mMap.valueAt(i);
+ if (!isValidType(value)) {
+ Slog.e(TAG, "Dropping bad data before persisting: "
+ + mMap.keyAt(i) + "=" + value);
+ mMap.removeAt(i);
+ }
+ }
XmlUtils.writeMapXml(mMap, out, this);
}
@@ -322,9 +345,12 @@ public final class PersistableBundle extends BaseBundle implements Cloneable, Pa
while (((event = in.next()) != XmlPullParser.END_DOCUMENT) &&
(event != XmlPullParser.END_TAG || in.getDepth() < outerDepth)) {
if (event == XmlPullParser.START_TAG) {
+ // Don't throw an exception when restoring from XML since an attacker could try to
+ // input invalid data in the persisted file.
return new PersistableBundle((ArrayMap<String, Object>)
XmlUtils.readThisArrayMapXml(in, startTag, tagName,
- new MyReadMapCallback()));
+ new MyReadMapCallback()),
+ /* throwException */ false);
}
}
return new PersistableBundle(); // An empty mutable PersistableBundle
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 61174baf7fd9..cbfc99871239 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -728,6 +728,11 @@ public class RemoteViews implements Parcelable, Filter {
mActions.get(i).visitUris(visitor);
}
}
+ if (mSizedRemoteViews != null) {
+ for (int i = 0; i < mSizedRemoteViews.size(); i++) {
+ mSizedRemoteViews.get(i).visitUris(visitor);
+ }
+ }
if (mLandscape != null) {
mLandscape.visitUris(visitor);
}
@@ -1842,7 +1847,7 @@ public class RemoteViews implements Parcelable, Filter {
}
@Override
- public final void visitUris(@NonNull Consumer<Uri> visitor) {
+ public void visitUris(@NonNull Consumer<Uri> visitor) {
switch (this.type) {
case URI:
final Uri uri = (Uri) getParameterValue(null);
@@ -2305,6 +2310,14 @@ public class RemoteViews implements Parcelable, Filter {
public int getActionTag() {
return NIGHT_MODE_REFLECTION_ACTION_TAG;
}
+
+ @Override
+ public void visitUris(@NonNull Consumer<Uri> visitor) {
+ if (this.type == ICON) {
+ visitIconUri((Icon) mDarkValue, visitor);
+ visitIconUri((Icon) mLightValue, visitor);
+ }
+ }
}
/**
diff --git a/core/jni/android_view_InputDevice.cpp b/core/jni/android_view_InputDevice.cpp
index 9cc72437a023..f7c770e0bffb 100644
--- a/core/jni/android_view_InputDevice.cpp
+++ b/core/jni/android_view_InputDevice.cpp
@@ -42,6 +42,13 @@ jobject android_view_InputDevice_create(JNIEnv* env, const InputDeviceInfo& devi
return NULL;
}
+ // b/274058082: Pass a copy of the key character map to avoid concurrent
+ // access
+ std::shared_ptr<KeyCharacterMap> map = deviceInfo.getKeyCharacterMap();
+ if (map != nullptr) {
+ map = std::make_shared<KeyCharacterMap>(*map);
+ }
+
ScopedLocalRef<jstring> descriptorObj(env,
env->NewStringUTF(deviceInfo.getIdentifier().descriptor.c_str()));
if (!descriptorObj.get()) {
@@ -49,8 +56,8 @@ jobject android_view_InputDevice_create(JNIEnv* env, const InputDeviceInfo& devi
}
ScopedLocalRef<jobject> kcmObj(env,
- android_view_KeyCharacterMap_create(env, deviceInfo.getId(),
- deviceInfo.getKeyCharacterMap()));
+ android_view_KeyCharacterMap_create(env, deviceInfo.getId(),
+ map));
if (!kcmObj.get()) {
return NULL;
}
diff --git a/core/tests/coretests/src/android/net/UriTest.java b/core/tests/coretests/src/android/net/UriTest.java
index 89632a46267e..2a4ca79d997e 100644
--- a/core/tests/coretests/src/android/net/UriTest.java
+++ b/core/tests/coretests/src/android/net/UriTest.java
@@ -25,8 +25,6 @@ import junit.framework.TestCase;
import java.io.File;
import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
@@ -869,84 +867,90 @@ public class UriTest extends TestCase {
return (Uri) hierarchicalUriConstructor.newInstance("https", authority, path, null, null);
}
- /** Attempting to unparcel a legacy parcel format of Uri.{,Path}Part should fail. */
- public void testUnparcelLegacyPart_fails() throws Exception {
- assertUnparcelLegacyPart_fails(Class.forName("android.net.Uri$Part"));
- assertUnparcelLegacyPart_fails(Class.forName("android.net.Uri$PathPart"));
- }
-
- private static void assertUnparcelLegacyPart_fails(Class partClass) throws Exception {
- Parcel parcel = Parcel.obtain();
- parcel.writeInt(0 /* BOTH */);
- parcel.writeString("encoded");
- parcel.writeString("decoded");
- parcel.setDataPosition(0);
-
- Method readFromMethod = partClass.getDeclaredMethod("readFrom", Parcel.class);
- readFromMethod.setAccessible(true);
- try {
- readFromMethod.invoke(null, parcel);
- fail();
- } catch (InvocationTargetException expected) {
- Throwable targetException = expected.getTargetException();
- // Check that the exception was thrown for the correct reason.
- assertEquals("Unknown representation: 0", targetException.getMessage());
- } finally {
- parcel.recycle();
- }
- }
-
- private Uri buildUriFromRawParcel(boolean argumentsEncoded,
+ private Uri buildUriFromParts(boolean argumentsEncoded,
String scheme,
String authority,
String path,
String query,
String fragment) {
- // Representation value (from AbstractPart.REPRESENTATION_{ENCODED,DECODED}).
- final int representation = argumentsEncoded ? 1 : 2;
- Parcel parcel = Parcel.obtain();
- try {
- parcel.writeInt(3); // hierarchical
- parcel.writeString8(scheme);
- parcel.writeInt(representation);
- parcel.writeString8(authority);
- parcel.writeInt(representation);
- parcel.writeString8(path);
- parcel.writeInt(representation);
- parcel.writeString8(query);
- parcel.writeInt(representation);
- parcel.writeString8(fragment);
- parcel.setDataPosition(0);
- return Uri.CREATOR.createFromParcel(parcel);
- } finally {
- parcel.recycle();
+ final Uri.Builder builder = new Uri.Builder();
+ builder.scheme(scheme);
+ if (argumentsEncoded) {
+ builder.encodedAuthority(authority);
+ builder.encodedPath(path);
+ builder.encodedQuery(query);
+ builder.encodedFragment(fragment);
+ } else {
+ builder.authority(authority);
+ builder.path(path);
+ builder.query(query);
+ builder.fragment(fragment);
}
+ return builder.build();
}
public void testUnparcelMalformedPath() {
// Regression tests for b/171966843.
// Test cases with arguments encoded (covering testing `scheme` * `authority` options).
- Uri uri0 = buildUriFromRawParcel(true, "https", "google.com", "@evil.com", null, null);
+ Uri uri0 = buildUriFromParts(true, "https", "google.com", "@evil.com", null, null);
assertEquals("https://google.com/@evil.com", uri0.toString());
- Uri uri1 = buildUriFromRawParcel(true, null, "google.com", "@evil.com", "name=spark", "x");
+ Uri uri1 = buildUriFromParts(true, null, "google.com", "@evil.com", "name=spark", "x");
assertEquals("//google.com/@evil.com?name=spark#x", uri1.toString());
- Uri uri2 = buildUriFromRawParcel(true, "http:", null, "@evil.com", null, null);
+ Uri uri2 = buildUriFromParts(true, "http:", null, "@evil.com", null, null);
assertEquals("http::/@evil.com", uri2.toString());
- Uri uri3 = buildUriFromRawParcel(true, null, null, "@evil.com", null, null);
+ Uri uri3 = buildUriFromParts(true, null, null, "@evil.com", null, null);
assertEquals("@evil.com", uri3.toString());
// Test cases with arguments not encoded (covering testing `scheme` * `authority` options).
- Uri uriA = buildUriFromRawParcel(false, "https", "google.com", "@evil.com", null, null);
+ Uri uriA = buildUriFromParts(false, "https", "google.com", "@evil.com", null, null);
assertEquals("https://google.com/%40evil.com", uriA.toString());
- Uri uriB = buildUriFromRawParcel(false, null, "google.com", "@evil.com", null, null);
+ Uri uriB = buildUriFromParts(false, null, "google.com", "@evil.com", null, null);
assertEquals("//google.com/%40evil.com", uriB.toString());
- Uri uriC = buildUriFromRawParcel(false, "http:", null, "@evil.com", null, null);
+ Uri uriC = buildUriFromParts(false, "http:", null, "@evil.com", null, null);
assertEquals("http::/%40evil.com", uriC.toString());
- Uri uriD = buildUriFromRawParcel(false, null, null, "@evil.com", "name=spark", "y");
+ Uri uriD = buildUriFromParts(false, null, null, "@evil.com", "name=spark", "y");
assertEquals("%40evil.com?name%3Dspark#y", uriD.toString());
}
+ public void testParsedUriFromStringEquality() {
+ Uri uri = buildUriFromParts(
+ true, "https", "google.com", "@evil.com", null, null);
+ assertEquals(uri, Uri.parse(uri.toString()));
+ Uri uri2 = buildUriFromParts(
+ true, "content://evil.authority?foo=", "safe.authority", "@evil.com", null, null);
+ assertEquals(uri2, Uri.parse(uri2.toString()));
+ Uri uri3 = buildUriFromParts(
+ false, "content://evil.authority?foo=", "safe.authority", "@evil.com", null, null);
+ assertEquals(uri3, Uri.parse(uri3.toString()));
+ }
+
+ public void testParceledUrisAreEqual() {
+ Uri opaqueUri = Uri.fromParts("fake://uri#", "ssp", "fragment");
+ Parcel parcel = Parcel.obtain();
+ try {
+ opaqueUri.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ Uri postParcelUri = Uri.CREATOR.createFromParcel(parcel);
+ Uri parsedUri = Uri.parse(postParcelUri.toString());
+ assertEquals(parsedUri.getScheme(), postParcelUri.getScheme());
+ } finally {
+ parcel.recycle();
+ }
+
+ Uri hierarchicalUri = new Uri.Builder().scheme("fake://uri#").authority("auth").build();
+ parcel = Parcel.obtain();
+ try {
+ hierarchicalUri.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ Uri postParcelUri = Uri.CREATOR.createFromParcel(parcel);
+ Uri parsedUri = Uri.parse(postParcelUri.toString());
+ assertEquals(parsedUri.getScheme(), postParcelUri.getScheme());
+ } finally {
+ parcel.recycle();
+ }
+ }
+
public void testToSafeString() {
checkToSafeString("tel:xxxxxx", "tel:Google");
checkToSafeString("tel:xxxxxxxxxx", "tel:1234567890");
diff --git a/core/tests/coretests/src/android/widget/RemoteViewsTest.java b/core/tests/coretests/src/android/widget/RemoteViewsTest.java
index 350b7fc2926f..a8f2b1d22aed 100644
--- a/core/tests/coretests/src/android/widget/RemoteViewsTest.java
+++ b/core/tests/coretests/src/android/widget/RemoteViewsTest.java
@@ -63,6 +63,7 @@ import org.junit.runner.RunWith;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Map;
+import java.util.HashMap;
import java.util.concurrent.CountDownLatch;
import java.util.function.Consumer;
@@ -720,6 +721,19 @@ public class RemoteViewsTest {
}
@Test
+ public void visitUris_themedIcons() {
+ RemoteViews views = new RemoteViews(mPackage, R.layout.remote_views_test);
+ final Icon iconLight = Icon.createWithContentUri("content://light/icon");
+ final Icon iconDark = Icon.createWithContentUri("content://dark/icon");
+ views.setIcon(R.id.layout, "setLargeIcon", iconLight, iconDark);
+
+ Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class);
+ views.visitUris(visitor);
+ verify(visitor, times(1)).accept(eq(iconLight.getUri()));
+ verify(visitor, times(1)).accept(eq(iconDark.getUri()));
+ }
+
+ @Test
public void visitUris_nestedViews() {
final RemoteViews outer = new RemoteViews(mPackage, R.layout.remote_views_test);
@@ -778,4 +792,43 @@ public class RemoteViewsTest {
verify(visitor, times(1)).accept(eq(icon3P.getUri()));
verify(visitor, times(1)).accept(eq(icon4P.getUri()));
}
+
+ @Test
+ public void visitUris_sizedViews() {
+ final RemoteViews large = new RemoteViews(mPackage, R.layout.remote_views_test);
+ final Uri imageUriL = Uri.parse("content://large/image");
+ final Icon icon1L = Icon.createWithContentUri("content://large/icon1");
+ final Icon icon2L = Icon.createWithContentUri("content://large/icon2");
+ final Icon icon3L = Icon.createWithContentUri("content://large/icon3");
+ final Icon icon4L = Icon.createWithContentUri("content://large/icon4");
+ large.setImageViewUri(R.id.image, imageUriL);
+ large.setTextViewCompoundDrawables(R.id.text, icon1L, icon2L, icon3L, icon4L);
+
+ final RemoteViews small = new RemoteViews(mPackage, 33);
+ final Uri imageUriS = Uri.parse("content://small/image");
+ final Icon icon1S = Icon.createWithContentUri("content://small/icon1");
+ final Icon icon2S = Icon.createWithContentUri("content://small/icon2");
+ final Icon icon3S = Icon.createWithContentUri("content://small/icon3");
+ final Icon icon4S = Icon.createWithContentUri("content://small/icon4");
+ small.setImageViewUri(R.id.image, imageUriS);
+ small.setTextViewCompoundDrawables(R.id.text, icon1S, icon2S, icon3S, icon4S);
+
+ HashMap<SizeF, RemoteViews> sizedViews = new HashMap<>();
+ sizedViews.put(new SizeF(300, 300), large);
+ sizedViews.put(new SizeF(100, 100), small);
+ RemoteViews views = new RemoteViews(sizedViews);
+
+ Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class);
+ views.visitUris(visitor);
+ verify(visitor, times(1)).accept(eq(imageUriL));
+ verify(visitor, times(1)).accept(eq(icon1L.getUri()));
+ verify(visitor, times(1)).accept(eq(icon2L.getUri()));
+ verify(visitor, times(1)).accept(eq(icon3L.getUri()));
+ verify(visitor, times(1)).accept(eq(icon4L.getUri()));
+ verify(visitor, times(1)).accept(eq(imageUriS));
+ verify(visitor, times(1)).accept(eq(icon1S.getUri()));
+ verify(visitor, times(1)).accept(eq(icon2S.getUri()));
+ verify(visitor, times(1)).accept(eq(icon3S.getUri()));
+ verify(visitor, times(1)).accept(eq(icon4S.getUri()));
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
index 6390c8984dac..47e7d80d50e3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
@@ -45,6 +45,7 @@ import android.content.Intent;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
@@ -509,13 +510,19 @@ public class PipMenuView extends FrameLayout {
final boolean isCloseAction = mCloseAction != null && Objects.equals(
mCloseAction.getActionIntent(), action.getActionIntent());
- // TODO: Check if the action drawable has changed before we reload it
- action.getIcon().loadDrawableAsync(mContext, d -> {
- if (d != null) {
- d.setTint(Color.WHITE);
- actionView.setImageDrawable(d);
- }
- }, mMainHandler);
+ final int iconType = action.getIcon().getType();
+ if (iconType == Icon.TYPE_URI || iconType == Icon.TYPE_URI_ADAPTIVE_BITMAP) {
+ // Disallow loading icon from content URI
+ actionView.setImageDrawable(null);
+ } else {
+ // TODO: Check if the action drawable has changed before we reload it
+ action.getIcon().loadDrawableAsync(mContext, d -> {
+ if (d != null) {
+ d.setTint(Color.WHITE);
+ actionView.setImageDrawable(d);
+ }
+ }, mMainHandler);
+ }
actionView.setCustomCloseBackgroundVisibility(
isCloseAction ? View.VISIBLE : View.GONE);
actionView.setContentDescription(action.getContentDescription());
diff --git a/libs/androidfw/CursorWindow.cpp b/libs/androidfw/CursorWindow.cpp
index 3527eeead1d5..2a6dc7b95c07 100644
--- a/libs/androidfw/CursorWindow.cpp
+++ b/libs/androidfw/CursorWindow.cpp
@@ -108,7 +108,7 @@ status_t CursorWindow::maybeInflate() {
{
// Migrate existing contents into new ashmem region
- uint32_t slotsSize = mSize - mSlotsOffset;
+ uint32_t slotsSize = sizeOfSlots();
uint32_t newSlotsOffset = mInflatedSize - slotsSize;
memcpy(static_cast<uint8_t*>(newData),
static_cast<uint8_t*>(mData), mAllocOffset);
@@ -216,11 +216,9 @@ status_t CursorWindow::writeToParcel(Parcel* parcel) {
if (parcel->writeDupFileDescriptor(mAshmemFd)) goto fail;
} else {
// Since we know we're going to be read-only on the remote side,
- // we can compact ourselves on the wire, with just enough padding
- // to ensure our slots stay aligned
- size_t slotsSize = mSize - mSlotsOffset;
- size_t compactedSize = mAllocOffset + slotsSize;
- compactedSize = (compactedSize + 3) & ~3;
+ // we can compact ourselves on the wire.
+ size_t slotsSize = sizeOfSlots();
+ size_t compactedSize = sizeInUse();
if (parcel->writeUint32(compactedSize)) goto fail;
if (parcel->writeBool(false)) goto fail;
void* dest = parcel->writeInplace(compactedSize);
diff --git a/libs/androidfw/include/androidfw/CursorWindow.h b/libs/androidfw/include/androidfw/CursorWindow.h
index 6e55a9a0eb8b..9ec026a19c4c 100644
--- a/libs/androidfw/include/androidfw/CursorWindow.h
+++ b/libs/androidfw/include/androidfw/CursorWindow.h
@@ -90,6 +90,9 @@ public:
inline uint32_t getNumRows() { return mNumRows; }
inline uint32_t getNumColumns() { return mNumColumns; }
+ inline size_t sizeOfSlots() const { return mSize - mSlotsOffset; }
+ inline size_t sizeInUse() const { return mAllocOffset + sizeOfSlots(); }
+
status_t clear();
status_t setNumColumns(uint32_t numColumns);
diff --git a/libs/androidfw/tests/CursorWindow_test.cpp b/libs/androidfw/tests/CursorWindow_test.cpp
index 15be80c48192..9ac427b66cb3 100644
--- a/libs/androidfw/tests/CursorWindow_test.cpp
+++ b/libs/androidfw/tests/CursorWindow_test.cpp
@@ -20,9 +20,16 @@
#include "TestHelpers.h"
+// Verify that the memory in use is a multiple of 4 bytes
+#define ASSERT_ALIGNED(w) \
+ ASSERT_EQ(((w)->sizeInUse() & 3), 0); \
+ ASSERT_EQ(((w)->freeSpace() & 3), 0); \
+ ASSERT_EQ(((w)->sizeOfSlots() & 3), 0)
+
#define CREATE_WINDOW_1K \
CursorWindow* w; \
- CursorWindow::create(String8("test"), 1 << 10, &w);
+ CursorWindow::create(String8("test"), 1 << 10, &w); \
+ ASSERT_ALIGNED(w);
#define CREATE_WINDOW_1K_3X3 \
CursorWindow* w; \
@@ -30,11 +37,13 @@
ASSERT_EQ(w->setNumColumns(3), OK); \
ASSERT_EQ(w->allocRow(), OK); \
ASSERT_EQ(w->allocRow(), OK); \
- ASSERT_EQ(w->allocRow(), OK);
+ ASSERT_EQ(w->allocRow(), OK); \
+ ASSERT_ALIGNED(w);
#define CREATE_WINDOW_2M \
CursorWindow* w; \
- CursorWindow::create(String8("test"), 1 << 21, &w);
+ CursorWindow::create(String8("test"), 1 << 21, &w); \
+ ASSERT_ALIGNED(w);
static constexpr const size_t kHalfInlineSize = 8192;
static constexpr const size_t kGiantSize = 1048576;
@@ -48,6 +57,7 @@ TEST(CursorWindowTest, Empty) {
ASSERT_EQ(w->getNumColumns(), 0);
ASSERT_EQ(w->size(), 1 << 10);
ASSERT_EQ(w->freeSpace(), 1 << 10);
+ ASSERT_ALIGNED(w);
}
TEST(CursorWindowTest, SetNumColumns) {
@@ -59,6 +69,7 @@ TEST(CursorWindowTest, SetNumColumns) {
ASSERT_NE(w->setNumColumns(5), OK);
ASSERT_NE(w->setNumColumns(3), OK);
ASSERT_EQ(w->getNumColumns(), 4);
+ ASSERT_ALIGNED(w);
}
TEST(CursorWindowTest, SetNumColumnsAfterRow) {
@@ -69,6 +80,7 @@ TEST(CursorWindowTest, SetNumColumnsAfterRow) {
ASSERT_EQ(w->allocRow(), OK);
ASSERT_NE(w->setNumColumns(4), OK);
ASSERT_EQ(w->getNumColumns(), 0);
+ ASSERT_ALIGNED(w);
}
TEST(CursorWindowTest, AllocRow) {
@@ -82,14 +94,17 @@ TEST(CursorWindowTest, AllocRow) {
ASSERT_EQ(w->allocRow(), OK);
ASSERT_LT(w->freeSpace(), before);
ASSERT_EQ(w->getNumRows(), 1);
+ ASSERT_ALIGNED(w);
// Verify we can unwind
ASSERT_EQ(w->freeLastRow(), OK);
ASSERT_EQ(w->freeSpace(), before);
ASSERT_EQ(w->getNumRows(), 0);
+ ASSERT_ALIGNED(w);
// Can't unwind when no rows left
ASSERT_NE(w->freeLastRow(), OK);
+ ASSERT_ALIGNED(w);
}
TEST(CursorWindowTest, AllocRowBounds) {
@@ -99,6 +114,7 @@ TEST(CursorWindowTest, AllocRowBounds) {
ASSERT_EQ(w->setNumColumns(60), OK);
ASSERT_EQ(w->allocRow(), OK);
ASSERT_NE(w->allocRow(), OK);
+ ASSERT_ALIGNED(w);
}
TEST(CursorWindowTest, StoreNull) {
@@ -115,6 +131,7 @@ TEST(CursorWindowTest, StoreNull) {
auto field = w->getFieldSlot(0, 0);
ASSERT_EQ(w->getFieldSlotType(field), CursorWindow::FIELD_TYPE_NULL);
}
+ ASSERT_ALIGNED(w);
}
TEST(CursorWindowTest, StoreLong) {
@@ -133,6 +150,7 @@ TEST(CursorWindowTest, StoreLong) {
ASSERT_EQ(w->getFieldSlotType(field), CursorWindow::FIELD_TYPE_INTEGER);
ASSERT_EQ(w->getFieldSlotValueLong(field), 0xcafe);
}
+ ASSERT_ALIGNED(w);
}
TEST(CursorWindowTest, StoreString) {
@@ -154,6 +172,7 @@ TEST(CursorWindowTest, StoreString) {
auto actual = w->getFieldSlotValueString(field, &size);
ASSERT_EQ(std::string(actual), "cafe");
}
+ ASSERT_ALIGNED(w);
}
TEST(CursorWindowTest, StoreBounds) {
@@ -174,6 +193,7 @@ TEST(CursorWindowTest, StoreBounds) {
ASSERT_EQ(w->getFieldSlot(-1, 0), nullptr);
ASSERT_EQ(w->getFieldSlot(0, -1), nullptr);
ASSERT_EQ(w->getFieldSlot(-1, -1), nullptr);
+ ASSERT_ALIGNED(w);
}
TEST(CursorWindowTest, Inflate) {
@@ -233,6 +253,7 @@ TEST(CursorWindowTest, Inflate) {
ASSERT_NE(actual, buf);
ASSERT_EQ(memcmp(buf, actual, kHalfInlineSize), 0);
}
+ ASSERT_ALIGNED(w);
}
TEST(CursorWindowTest, ParcelEmpty) {
@@ -248,10 +269,12 @@ TEST(CursorWindowTest, ParcelEmpty) {
ASSERT_EQ(w->getNumColumns(), 0);
ASSERT_EQ(w->size(), 0);
ASSERT_EQ(w->freeSpace(), 0);
+ ASSERT_ALIGNED(w);
// We can't mutate the window after parceling
ASSERT_NE(w->setNumColumns(4), OK);
ASSERT_NE(w->allocRow(), OK);
+ ASSERT_ALIGNED(w);
}
TEST(CursorWindowTest, ParcelSmall) {
@@ -310,6 +333,7 @@ TEST(CursorWindowTest, ParcelSmall) {
ASSERT_EQ(actualSize, 0);
ASSERT_NE(actual, nullptr);
}
+ ASSERT_ALIGNED(w);
}
TEST(CursorWindowTest, ParcelLarge) {
@@ -362,6 +386,7 @@ TEST(CursorWindowTest, ParcelLarge) {
ASSERT_EQ(actualSize, 0);
ASSERT_NE(actual, nullptr);
}
+ ASSERT_ALIGNED(w);
}
} // android
diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java
index 27727699d05c..19720c2ed8f9 100644
--- a/media/java/android/media/RingtoneManager.java
+++ b/media/java/android/media/RingtoneManager.java
@@ -776,10 +776,10 @@ public class RingtoneManager {
return ringtoneUri;
}
-
+
/**
* Sets the {@link Uri} of the default sound for a given sound type.
- *
+ *
* @param context A context used for querying.
* @param type The type whose default sound should be set. One of
* {@link #TYPE_RINGTONE}, {@link #TYPE_NOTIFICATION}, or
@@ -795,6 +795,21 @@ public class RingtoneManager {
if(!isInternalRingtoneUri(ringtoneUri)) {
ringtoneUri = ContentProvider.maybeAddUserId(ringtoneUri, context.getUserId());
}
+
+ if (ringtoneUri != null) {
+ final String mimeType = resolver.getType(ringtoneUri);
+ if (mimeType == null) {
+ Log.e(TAG, "setActualDefaultRingtoneUri for URI:" + ringtoneUri
+ + " ignored: failure to find mimeType (no access from this context?)");
+ return;
+ }
+ if (!(mimeType.startsWith("audio/") || mimeType.equals("application/ogg"))) {
+ Log.e(TAG, "setActualDefaultRingtoneUri for URI:" + ringtoneUri
+ + " ignored: associated mimeType:" + mimeType + " is not an audio type");
+ return;
+ }
+ }
+
Settings.System.putStringForUser(resolver, setting,
ringtoneUri != null ? ringtoneUri.toString() : null, context.getUserId());
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
index b5e4fa38d244..af06d7304160 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
@@ -243,7 +243,9 @@ public class RestrictedSwitchPreference extends SwitchPreference {
return mHelper != null ? mHelper.packageName : null;
}
- public void updateState(@NonNull String packageName, int uid, boolean isEnabled) {
+ /** Updates enabled state based on associated package. */
+ public void updateState(
+ @NonNull String packageName, int uid, boolean isEnableAllowed, boolean isEnabled) {
mHelper.updatePackageDetails(packageName, uid);
if (mAppOpsManager == null) {
mAppOpsManager = getContext().getSystemService(AppOpsManager.class);
@@ -254,7 +256,9 @@ public class RestrictedSwitchPreference extends SwitchPreference {
final boolean ecmEnabled = getContext().getResources().getBoolean(
com.android.internal.R.bool.config_enhancedConfirmationModeEnabled);
final boolean appOpsAllowed = !ecmEnabled || mode == AppOpsManager.MODE_ALLOWED;
- if (isEnabled) {
+ if (!isEnableAllowed && !isEnabled) {
+ setEnabled(false);
+ } else if (isEnabled) {
setEnabled(true);
} else if (appOpsAllowed && isDisabledByAppOps()) {
setEnabled(true);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index a6edb0f0e2e3..f80d587058f1 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -1928,6 +1928,9 @@ public class SettingsProvider extends ContentProvider {
cacheName = Settings.System.ALARM_ALERT_CACHE;
}
if (cacheName != null) {
+ if (!isValidAudioUri(name, value)) {
+ return false;
+ }
final File cacheFile = new File(
getRingtoneCacheDir(owningUserId), cacheName);
cacheFile.delete();
@@ -1960,6 +1963,34 @@ public class SettingsProvider extends ContentProvider {
}
}
+ private boolean isValidAudioUri(String name, String uri) {
+ if (uri != null) {
+ Uri audioUri = Uri.parse(uri);
+ if (Settings.AUTHORITY.equals(
+ ContentProvider.getAuthorityWithoutUserId(audioUri.getAuthority()))) {
+ // Don't accept setting the default uri to self-referential URIs like
+ // Settings.System.DEFAULT_RINGTONE_URI, which is an alias to the value of this
+ // setting.
+ return false;
+ }
+ final String mimeType = getContext().getContentResolver().getType(audioUri);
+ if (mimeType == null) {
+ Slog.e(LOG_TAG,
+ "mutateSystemSetting for setting: " + name + " URI: " + audioUri
+ + " ignored: failure to find mimeType (no access from this context?)");
+ return false;
+ }
+ if (!(mimeType.startsWith("audio/") || mimeType.equals("application/ogg")
+ || mimeType.equals("application/x-flac"))) {
+ Slog.e(LOG_TAG,
+ "mutateSystemSetting for setting: " + name + " URI: " + audioUri
+ + " ignored: associated mimeType: " + mimeType + " is not an audio type");
+ return false;
+ }
+ }
+ return true;
+ }
+
private boolean hasWriteSecureSettingsPermission() {
// Write secure settings is a more protected permission. If caller has it we are good.
return getContext().checkCallingOrSelfPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
@@ -3101,6 +3132,15 @@ public class SettingsProvider extends ContentProvider {
return settingsState.getSettingLocked(name);
}
+ private boolean shouldExcludeSettingFromReset(Setting setting, String prefix) {
+ // If a prefix was specified, exclude settings whose names don't start with it.
+ if (prefix != null && !setting.getName().startsWith(prefix)) {
+ return true;
+ }
+ // Never reset SECURE_FRP_MODE, as it could be abused to bypass FRP via RescueParty.
+ return Secure.SECURE_FRP_MODE.equals(setting.getName());
+ }
+
public void resetSettingsLocked(int type, int userId, String packageName, int mode,
String tag) {
resetSettingsLocked(type, userId, packageName, mode, tag, /*prefix=*/
@@ -3123,7 +3163,7 @@ public class SettingsProvider extends ContentProvider {
Setting setting = settingsState.getSettingLocked(name);
if (packageName.equals(setting.getPackageName())) {
if ((tag != null && !tag.equals(setting.getTag()))
- || (prefix != null && !setting.getName().startsWith(prefix))) {
+ || shouldExcludeSettingFromReset(setting, prefix)) {
continue;
}
if (settingsState.resetSettingLocked(name)) {
@@ -3143,7 +3183,7 @@ public class SettingsProvider extends ContentProvider {
Setting setting = settingsState.getSettingLocked(name);
if (!SettingsState.isSystemPackage(getContext(),
setting.getPackageName())) {
- if (prefix != null && !setting.getName().startsWith(prefix)) {
+ if (shouldExcludeSettingFromReset(setting, prefix)) {
continue;
}
if (settingsState.resetSettingLocked(name)) {
@@ -3163,7 +3203,7 @@ public class SettingsProvider extends ContentProvider {
Setting setting = settingsState.getSettingLocked(name);
if (!SettingsState.isSystemPackage(getContext(),
setting.getPackageName())) {
- if (prefix != null && !setting.getName().startsWith(prefix)) {
+ if (shouldExcludeSettingFromReset(setting, prefix)) {
continue;
}
if (setting.isDefaultFromSystem()) {
@@ -3186,7 +3226,7 @@ public class SettingsProvider extends ContentProvider {
for (String name : settingsState.getSettingNamesLocked()) {
Setting setting = settingsState.getSettingLocked(name);
boolean someSettingChanged = false;
- if (prefix != null && !setting.getName().startsWith(prefix)) {
+ if (shouldExcludeSettingFromReset(setting, prefix)) {
continue;
}
if (setting.isDefaultFromSystem()) {
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java
index eaf0dcb9b4e7..1c6d2b08136c 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java
@@ -464,6 +464,31 @@ public class SettingsProviderTest extends BaseSettingsProviderTest {
}
}
+ // To prevent FRP bypasses, the SECURE_FRP_MODE setting should not be reset when all other
+ // settings are reset. But it should still be possible to explicitly set its value.
+ @Test
+ public void testSecureFrpModeSettingCannotBeReset() throws Exception {
+ final String name = Settings.Secure.SECURE_FRP_MODE;
+ final String origValue = getSetting(SETTING_TYPE_GLOBAL, name);
+ setSettingViaShell(SETTING_TYPE_GLOBAL, name, "1", false);
+ try {
+ assertEquals("1", getSetting(SETTING_TYPE_GLOBAL, name));
+ for (int type : new int[] { SETTING_TYPE_GLOBAL, SETTING_TYPE_SECURE }) {
+ resetSettingsViaShell(type, Settings.RESET_MODE_UNTRUSTED_DEFAULTS);
+ resetSettingsViaShell(type, Settings.RESET_MODE_UNTRUSTED_CHANGES);
+ resetSettingsViaShell(type, Settings.RESET_MODE_TRUSTED_DEFAULTS);
+ }
+ // The value should still be "1". It should not have been reset to null.
+ assertEquals("1", getSetting(SETTING_TYPE_GLOBAL, name));
+ // It should still be possible to explicitly set the value to "0".
+ setSettingViaShell(SETTING_TYPE_GLOBAL, name, "0", false);
+ assertEquals("0", getSetting(SETTING_TYPE_GLOBAL, name));
+ } finally {
+ setSettingViaShell(SETTING_TYPE_GLOBAL, name, origValue, false);
+ assertEquals(origValue, getSetting(SETTING_TYPE_GLOBAL, name));
+ }
+ }
+
private void doTestQueryStringInBracketsViaProviderApiForType(int type) {
// Make sure we have a clean slate.
deleteStringViaProviderApi(type, FAKE_SETTING_NAME);
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index cbfcfd20d760..3e4397b32273 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Beweeg nader aan <xliff:g id="DEVICENAME">%1$s</xliff:g> om hier te speel"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Speel tans op <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Iets is fout. Probeer weer."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> loop tans"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Onaktief, gaan program na"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Nie gekry nie"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrole is nie beskikbaar nie"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index fe7218b3753c..2a246f986035 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"እዚህ ለመጫወት ወደ <xliff:g id="DEVICENAME">%1$s</xliff:g> ቀረብ ይበሉ"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"በ<xliff:g id="DEVICENAME">%1$s</xliff:g> ላይ በማጫወት ላይ"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"የሆነ ችግር ተፈጥሯል። እንደገና ይሞክሩ።"</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> እያሄደ ነው"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"ንቁ ያልኾነ፣ መተግበሪያን ይፈትሹ"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"አልተገኘም"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"መቆጣጠሪያ አይገኝም"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index a98c36420b01..87a7615eb0a2 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -849,6 +849,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"يُرجى الاقتراب من <xliff:g id="DEVICENAME">%1$s</xliff:g> لتشغيل الوسائط هنا."</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"جارٍ تشغيل الوسائط على <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"حدث خطأ. يُرجى إعادة المحاولة."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"\"<xliff:g id="APP_NAME">%1$s</xliff:g>\" قيد التشغيل"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"غير نشط، تحقّق من التطبيق."</string>
<string name="controls_error_removed" msgid="6675638069846014366">"لم يتم العثور عليه."</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"عنصر التحكّم غير متوفّر"</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 71b4716ae9ea..a5812da704e4 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"ইয়াত খেলিবলৈ <xliff:g id="DEVICENAME">%1$s</xliff:g>ৰ আৰু ওচৰলৈ যাওক"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g>ত প্লে কৰি থকা হৈছে"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"কিবা ভুল হ’ল। পুনৰ চেষ্টা কৰক।"</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> চলি আছে"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"সক্ৰিয় নহয়, এপ্‌টো পৰীক্ষা কৰক"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"বিচাৰি পোৱা নগ’ল"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"নিয়ন্ত্ৰণটো উপলব্ধ নহয়"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index f1a3c69eed5d..ed6fec142354 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Burada oxutmaq üçün <xliff:g id="DEVICENAME">%1$s</xliff:g> cihazına yaxınlaşın"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> cihazında oxudulur"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Xəta oldu. Yenə cəhd edin."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> işləyir"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Aktiv deyil, tətbiqi yoxlayın"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Tapılmadı"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Nəzarət əlçatan deyil"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 28b5923761b5..82b62402af30 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -831,6 +831,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Približite se uređaju <xliff:g id="DEVICENAME">%1$s</xliff:g> da biste na njemu puštali"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Pušta se na uređaju <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Došlo je do greške. Probajte ponovo."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> je pokrenuta"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Neaktivno. Vidite aplikaciju"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Nije pronađeno"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrola nije dostupna"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 46b3013025e8..2dce9c4cd336 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -837,6 +837,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Падыдзіце бліжэй да прылады \"<xliff:g id="DEVICENAME">%1$s</xliff:g>\", каб прайграць на гэтай"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Прайграецца на прыладзе \"<xliff:g id="DEVICENAME">%1$s</xliff:g>\""</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Нешта пайшло не так. Паўтарыце спробу."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> працуе"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Неактыўна, праверце праграму"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Не знойдзена"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Кіраванне недаступнае"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 3837fe48ada7..1c2437b5108c 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Приближете се до <xliff:g id="DEVICENAME">%1$s</xliff:g> за възпроизвеждане на това устройство"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Възпроизвежда се на <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Нещо се обърка. Опитайте отново."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> се изпълнява"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Неактивно, проверете прилож."</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Не е намерено"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Контролата не е налице"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 3a351e68c17d..867918802bb4 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"এখান থেকে চালাতে <xliff:g id="DEVICENAME">%1$s</xliff:g>-এর কাছে নিয়ে যান"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g>-এ ভিডিও চালানো হচ্ছে"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"কোনও সমস্যা হয়েছে। আবার চেষ্টা করুন।"</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> চলছে"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"বন্ধ আছে, অ্যাপ চেক করুন"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"খুঁজে পাওয়া যায়নি"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"কন্ট্রোল উপলভ্য নেই"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 2569f54a824a..521f602ea0f2 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -831,6 +831,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Približite se uređaju <xliff:g id="DEVICENAME">%1$s</xliff:g> da na njemu reproducirate"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Reproducira se na uređaju <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Nešto nije uredu. Pokušajte ponovo."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> je pokrenuta"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Neaktivno, vidite aplikaciju"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Nije pronađeno"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrola nije dostupna"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index e777795de587..4e9208936ac5 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Acosta\'t a <xliff:g id="DEVICENAME">%1$s</xliff:g> per reproduir el contingut aquí"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"S\'està reproduint a <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"S\'ha produït un error. Torna-ho a provar."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> s\'està executant"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inactiu; comprova l\'aplicació"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"No s\'ha trobat"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"El control no està disponible"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index a9a3dc12d11a..785a7c2dbe71 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -837,6 +837,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Pokud zde chcete přehrávat média, přibližte se k zařízení <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Přehrávání v zařízení <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Došlo k chybě. Zkuste to znovu."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> je spuštěna"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Neaktivní, zkontrolujte aplikaci"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Nenalezeno"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Ovládání není k dispozici"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 85325be56297..fdf1b478d1d9 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Ryk tættere på <xliff:g id="DEVICENAME">%1$s</xliff:g> for at afspille her"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Afspilles på <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Noget gik galt. Prøv igen."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> kører"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inaktiv. Tjek appen"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Ikke fundet"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Styringselement ikke tilgængeligt"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 41bfa4ab5a3f..a1da2560bda7 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Platziere für die Wiedergabe dein Gerät näher an „<xliff:g id="DEVICENAME">%1$s</xliff:g>“"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Wird auf „<xliff:g id="DEVICENAME">%1$s</xliff:g>“ abgespielt"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Es gab ein Problem. Versuch es noch einmal."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> wird ausgeführt"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inaktiv – sieh in der App nach"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Nicht gefunden"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Steuerelement nicht verfügbar"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 67d18fcc0814..381572c8d517 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Μετακινηθείτε πιο κοντά στη συσκευή <xliff:g id="DEVICENAME">%1$s</xliff:g> για αναπαραγωγή εδώ"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Αναπαραγωγή στη συσκευή <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Παρουσιάστηκε κάποιο πρόβλημα. Δοκιμάστε ξανά."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> εκτελείται"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Ανενεργό, έλεγχος εφαρμογής"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Δεν βρέθηκε."</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Μη διαθέσιμο στοιχείο ελέγχου"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 0915843e0127..f51bd3af6e7d 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Move closer to <xliff:g id="DEVICENAME">%1$s</xliff:g> to play here"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Playing on <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Something went wrong. Try again."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> is running"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inactive, check app"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Not found"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Control is unavailable"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 3fed8c8a555c..e4f4b0041114 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Move closer to <xliff:g id="DEVICENAME">%1$s</xliff:g> to play here"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Playing on <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Something went wrong. Try again."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> is running"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inactive, check app"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Not found"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Control is unavailable"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 0915843e0127..f51bd3af6e7d 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Move closer to <xliff:g id="DEVICENAME">%1$s</xliff:g> to play here"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Playing on <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Something went wrong. Try again."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> is running"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inactive, check app"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Not found"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Control is unavailable"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 0915843e0127..f51bd3af6e7d 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Move closer to <xliff:g id="DEVICENAME">%1$s</xliff:g> to play here"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Playing on <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Something went wrong. Try again."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> is running"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inactive, check app"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Not found"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Control is unavailable"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index f24456042647..8f4574e5ab36 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‎‎‎‏‎‎‏‏‎‎‎‎‏‏‎‎‏‎‏‎‎‏‏‏‏‎‏‎‎‏‏‎‏‏‏‎‎‎‏‏‏‏‎‏‏‎‏‎‏‎‏‎‎‏‎‎‎‎Move closer to ‎‏‎‎‏‏‎<xliff:g id="DEVICENAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ to play here‎‏‎‎‏‎"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‏‏‎‏‏‏‏‎‎‏‎‏‎‏‎‏‎‎‏‎‏‎‎‏‏‏‏‏‎‎‎‎‎‏‏‏‏‎‏‏‏‎‏‏‎‎‎‏‏‎‎‎‎‏‎‏‎‎Playing on ‎‏‎‎‏‏‎<xliff:g id="DEVICENAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‏‎‎‏‏‏‎‎‎‏‏‎‎‏‎‎‏‏‎‎‎‎‏‏‏‎‎‏‏‏‏‏‎‎‎‎‎‏‎‏‎‏‏‎‏‎‏‏‎‎‏‎‏‏‎Something went wrong. Try again.‎‏‎‎‏‎"</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‎‎‏‎‎‎‎‏‏‎‏‎‏‏‎‏‏‎‏‎‎‎‎‎‎‏‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‏‏‎‏‎‏‎‏‏‎‎‏‏‎‏‎‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ is running‎‏‎‎‏‎"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‏‎‎‎‎‎‏‎‏‏‎‎‎‏‏‏‎‎‎‏‏‏‎‏‎‎‎‏‎‏‎‏‎‎‏‏‏‏‎‏‏‎‏‎‎‎‎‏‎‎‏‏‏‏‏‏‎‎Inactive, check app‎‏‎‎‏‎"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‎‏‎‎‏‎‎‏‎‏‎‎‎‎‏‎‏‏‏‎‏‎‎‏‎‎‏‏‎‏‎‎‎‏‏‏‏‏‎‏‏‏‏‏‎‎‏‏‎‎‏‏‏‏‎‎Not found‎‏‎‎‏‎"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‎‏‏‎‎‎‎‏‎‏‏‏‏‎‎‏‏‎‎‎‏‎‎‏‎‏‎‎‏‎‏‎‎‎‎‎‏‎‏‎‎‏‎‎‎‎‏‎‎‏‏‎‎‏‎‏‎‎Control is unavailable‎‏‎‎‏‎"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index b24fe007cd01..2149563c9aa4 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -831,6 +831,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Acércate a <xliff:g id="DEVICENAME">%1$s</xliff:g> para reproducir aquí"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Reproduciendo en <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Se produjo un error. Vuelve a intentarlo."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> se está ejecutando"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inactivo. Verifica la app"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"No se encontró"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"El control no está disponible"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 1d0bdd29f0cb..eae850d6798c 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -831,6 +831,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Acércate a <xliff:g id="DEVICENAME">%1$s</xliff:g> para jugar aquí"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Reproduciendo en <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Se ha producido un error. Inténtalo de nuevo."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> se está ejecutando"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inactivo, comprobar aplicación"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"No se ha encontrado"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Control no disponible"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 46f9f518628c..3bcfc0b7c319 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Siin esitamiseks liigutage seadmele <xliff:g id="DEVICENAME">%1$s</xliff:g> lähemale"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Esitatakse seadmes <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Midagi läks valesti. Proovige uuesti."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> töötab"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Passiivne, vaadake rakendust"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Ei leitud"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Juhtelement pole saadaval"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 5c79b1d932f9..60b2902df8bc 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Gerturatu <xliff:g id="DEVICENAME">%1$s</xliff:g> gailura bertan erreproduzitzen ari dena hemen erreproduzitzeko"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> gailuan erreproduzitzen"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Arazoren bat izan da. Saiatu berriro."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> abian da"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inaktibo; egiaztatu aplikazioa"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Ez da aurkitu"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Ez dago erabilgarri kontrolatzeko aukera"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index fb3a29b711d0..51c1965fe750 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"برای پخش در اینجا، به <xliff:g id="DEVICENAME">%1$s</xliff:g> نزدیک‌تر شوید"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"درحال پخش در <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"مشکلی پیش آمد. دوباره امتحان کنید."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> در حال اجرا است"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"غیرفعال، برنامه را بررسی کنید"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"پیدا نشد"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"کنترل دردسترس نیست"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index d1cdb9f0fb19..8337374441c9 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Siirrä <xliff:g id="DEVICENAME">%1$s</xliff:g> lähemmäs toistaaksesi täällä"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Toistetaan: <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Jotain meni pieleen. Yritä uudelleen."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> on käynnissä"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Epäaktiivinen, tarkista sovellus"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Ei löydy"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Ohjain ei ole käytettävissä"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index c9ee3dbf38ea..89fb05738f17 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -831,6 +831,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Rapprochez-vous de <xliff:g id="DEVICENAME">%1$s</xliff:g> pour lire le contenu"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Lecture sur <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Un problème est survenu. Réessayez."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> en cours d\'exécution"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Délai expiré, vérifiez l\'appli"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Introuvable"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"La commande n\'est pas accessible"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 5a41888ccb7f..454c599f28c3 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -831,6 +831,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Rapprochez l\'appareil pour transférer la diffusion à votre <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Lecture sur <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Un problème est survenu. Réessayez."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> est en cours d\'exécution"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Délai expiré, vérifier l\'appli"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Introuvable"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Commande indisponible"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index e64891850f44..b57befcff7c8 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Achégate ao dispositivo (<xliff:g id="DEVICENAME">%1$s</xliff:g>) para reproducir o contido neste"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Reproducindo contido noutro dispositivo (<xliff:g id="DEVICENAME">%1$s</xliff:g>)"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Produciuse un erro. Téntao de novo."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> estase executando"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inactivo. Comproba a app"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Non se atopou"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"O control non está dispoñible"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index ecdccde5ca3f..1a1a4c2cb616 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"આમાં ચલાવવા માટે ડિવાઇસને <xliff:g id="DEVICENAME">%1$s</xliff:g>ની નજીક ખસેડો"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> પર ચલાવવામાં આવી રહ્યું છે"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"કંઈક ખોટું થયું. ફરી પ્રયાસ કરો."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> ચાલી રહી છે"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"નિષ્ક્રિય, ઍપને ચેક કરો"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"મળ્યું નથી"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"નિયંત્રણ ઉપલબ્ધ નથી"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index d862adce3daf..dec6940d399e 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"अपने डिवाइस पर मीडिया फ़ाइल ट्रांसफ़र करने के लिए, उसे <xliff:g id="DEVICENAME">%1$s</xliff:g> के पास ले जाएं"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> पर मीडिया चल रहा है"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"कोई गड़बड़ी हुई. फिर से कोशिश करें."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> चालू है"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"काम नहीं कर रहा, ऐप जांचें"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"कंट्रोल नहीं है"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"कंट्रोल मौजूद नहीं है"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index e34a08e624af..afa1dc50f845 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -831,6 +831,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Približite se uređaju <xliff:g id="DEVICENAME">%1$s</xliff:g> da biste na njemu reproducirali"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Reproducira se na uređaju <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Nešto nije u redu. Pokušajte ponovo."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> je pokrenuta"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Neaktivno, provjerite aplik."</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Nije pronađeno"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrola nije dostupna"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 271b1ebecb3c..843ca5ee3473 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Menjen közelebb a(z) <xliff:g id="DEVICENAME">%1$s</xliff:g> eszközhöz, hogy itt játszhassa le a tartalmat"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Lejátszás folyamatban a(z) <xliff:g id="DEVICENAME">%1$s</xliff:g> eszközön"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Hiba történt. Próbálkozzon újra."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> jelenleg fut"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inaktív, ellenőrizze az appot"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Nem található"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Nem hozzáférhető vezérlő"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 56aa83ab840c..95561d3f4e19 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Ավելի մոտեցեք «<xliff:g id="DEVICENAME">%1$s</xliff:g>» սարքին՝ նվագարկումը սկսելու համար"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Նվագարկվում է «<xliff:g id="DEVICENAME">%1$s</xliff:g>» սարքում"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Սխալ առաջացավ։ Նորից փորձեք։"</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածն աշխատում է"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Ակտիվ չէ, ստուգեք հավելվածը"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Չի գտնվել"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Կառավարման տարրը հասանելի չէ"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 30f7b526093d..60122664a4b3 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Dekatkan ke <xliff:g id="DEVICENAME">%1$s</xliff:g> untuk memutar di sini"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Diputar di <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Terjadi error. Coba lagi."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> sedang berjalan"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Nonaktif, periksa aplikasi"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Tidak ditemukan"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrol tidak tersedia"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index c786d0d79c06..96eb447f2ccb 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Færðu tækið nær <xliff:g id="DEVICENAME">%1$s</xliff:g> til að spila hér"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Í spilun í <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Eitthvað fór úrskeiðis. Reyndu aftur."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> er í gangi"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Óvirkt, athugaðu forrit"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Fannst ekki"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Stýring er ekki tiltæk"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 1d87916753b8..45feb9350261 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -831,6 +831,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Avvicinati a <xliff:g id="DEVICENAME">%1$s</xliff:g> per riprodurre i contenuti qui"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"In riproduzione su <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Si è verificato un errore. Riprova."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> è in esecuzione"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inattivo, controlla l\'app"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Controllo non trovato"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Il controllo non è disponibile"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 56fb50e6ad6b..a332f871f9b9 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -837,6 +837,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"צריך להתקרב אל <xliff:g id="DEVICENAME">%1$s</xliff:g> כדי להפעיל כאן"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"פועלת ב-<xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"משהו השתבש. יש לנסות שוב."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"אפליקציית <xliff:g id="APP_NAME">%1$s</xliff:g> פועלת"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"לא פעיל, יש לבדוק את האפליקציה"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"לא נמצא"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"הפקד לא זמין"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index d4ea688d26ed..4f871eff7f90 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"ここで再生するには<xliff:g id="DEVICENAME">%1$s</xliff:g>に近づいてください"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g>で再生しています"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"エラーが発生しました。もう一度お試しください。"</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> を実行しています"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"無効: アプリをご確認ください"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"見つかりませんでした"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"コントロールを使用できません"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 30e92b716dd4..fd969352f007 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"მიუახლოვდით <xliff:g id="DEVICENAME">%1$s</xliff:g>-ს მისი მეშვეობით დასაკრავად"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"მიმდინარეობს დაკვრა <xliff:g id="DEVICENAME">%1$s</xliff:g>-ზე"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"რაღაც შეცდომა მოხდა. ცადეთ ხელახლა."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> გაშვებულია"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"არააქტიურია, გადაამოწმეთ აპი"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"ვერ მოიძებნა"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"კონტროლი მიუწვდომელია"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 71f5e76c2d80..d042926e0579 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Осы жерде ойнау үшін <xliff:g id="DEVICENAME">%1$s</xliff:g> құрылғысына жақындаңыз"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> құрылғысында ойнатылуда."</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Бірдеңе дұрыс болмады. Қайталап көріңіз."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> қосулы тұр"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Өшірулі. Қолданба тексеріңіз."</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Табылмады"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Басқару виджеті қолжетімсіз"</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 32b274fb560e..dbd8ea290cfe 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"រំកិលឱ្យកាន់តែជិត <xliff:g id="DEVICENAME">%1$s</xliff:g> ដើម្បីចាក់នៅទីនេះ"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"កំពុង​ចាក់​​នៅ​លើ <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"មានអ្វីមួយខុសប្រក្រតី។ សូមព្យាយាមម្ដងទៀត។"</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> កំពុង​ដំណើរការ"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"អសកម្ម ពិនិត្យមើល​កម្មវិធី"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"រកមិន​ឃើញទេ"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"មិនអាច​គ្រប់គ្រង​បានទេ"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 8198d7f7bc99..26158e0b1f9d 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"ಇಲ್ಲಿ ಪ್ಲೇ ಮಾಡಲು <xliff:g id="DEVICENAME">%1$s</xliff:g> ಸಮೀಪಕ್ಕೆ ಹೋಗಿ"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> ನಲ್ಲಿ ಪ್ಲೇ ಆಗುತ್ತಿದೆ"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"ಏನೋ ತಪ್ಪಾಗಿದೆ. ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> ರನ್ ಆಗುತ್ತಿದೆ"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"ನಿಷ್ಕ್ರಿಯ, ಆ್ಯಪ್ ಪರಿಶೀಲಿಸಿ"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"ಕಂಡುಬಂದಿಲ್ಲ"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"ನಿಯಂತ್ರಣ ಲಭ್ಯವಿಲ್ಲ"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 0fc7511693e2..4d47843503f6 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"현재 기기에서 재생하려면 <xliff:g id="DEVICENAME">%1$s</xliff:g>에 더 가까이 이동합니다."</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g>에서 재생 중"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"문제가 발생했습니다. 다시 시도해 주세요."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> 실행 중"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"비활성. 앱을 확인하세요."</string>
<string name="controls_error_removed" msgid="6675638069846014366">"찾을 수 없음"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"컨트롤을 사용할 수 없음"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 46d387c36191..4458e337a838 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Бул жерде ойнотуу үчүн <xliff:g id="DEVICENAME">%1$s</xliff:g> түзмөгүнө жакындатыңыз"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> аркылуу ойнотулууда"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Бир жерден ката кетти. Кайра аракет кылыңыз."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> иштеп жатат"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Жигерсиз. Колдонмону текшериңиз"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Табылган жок"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Башкара албайсыз"</string>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index cb86e04c2100..6640055fe802 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"ກະລຸນາຍ້າຍເຂົ້າໃກ້ <xliff:g id="DEVICENAME">%1$s</xliff:g> ເພື່ອຫຼິ້ນຢູ່ບ່ອນນີ້"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"ກຳລັງຫຼິ້ນຢູ່ <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"ມີບາງຢ່າງຜິດພາດເກີດຂຶ້ນ. ກະລຸນາລອງໃໝ່."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> ກຳລັງເຮັດວຽກຢູ່"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"ບໍ່ເຮັດວຽກ, ກະລຸນາກວດສອບແອັບ"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"ບໍ່ພົບ"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"ບໍ່ສາມາດໃຊ້ການຄວບຄຸມໄດ້"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 0df0af28b03d..5cf8091b1b86 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -837,6 +837,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Perkelkite arčiau „<xliff:g id="DEVICENAME">%1$s</xliff:g>“, kad būtų galima leisti čia"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Leidžiama įrenginyje „<xliff:g id="DEVICENAME">%1$s</xliff:g>“"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Kažkas ne taip. Bandykite dar kartą."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ vykdoma"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Neaktyvu, patikrinkite progr."</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Nerasta"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Valdiklis nepasiekiamas"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index a2490d6c0bf4..b15a9dc4f6aa 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -831,6 +831,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Pārvietojieties tuvāk ierīcei “<xliff:g id="DEVICENAME">%1$s</xliff:g>”, lai atskaņotu šeit"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Notiek atskaņošana ierīcē <xliff:g id="DEVICENAME">%1$s</xliff:g>."</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Radās kļūda. Mēģiniet vēlreiz."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"Lietotne <xliff:g id="APP_NAME">%1$s</xliff:g> darbojas"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Neaktīva, pārbaudiet lietotni"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Netika atrasta"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Vadīkla nav pieejama"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index a5afc6031f0a..94e390ce8f54 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Приближете се до <xliff:g id="DEVICENAME">%1$s</xliff:g> за да пуштите тука"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Пуштено на <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Нешто не е во ред. Обидете се повторно."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> работи"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Неактивна, провери апликација"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Не е најдено"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Контролата не е достапна"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 97960e8f3588..6d2235642aa1 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"ഇവിടെ പ്ലേ ചെയ്യാൻ <xliff:g id="DEVICENAME">%1$s</xliff:g> എന്നതിന് അടുത്തേക്ക് നീക്കുക"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> എന്നതിൽ പ്ലേ ചെയ്യുന്നു"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"എന്തോ കുഴപ്പമുണ്ടായി. വീണ്ടും ശ്രമിക്കുക."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> റൺ ചെയ്യുന്നു"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"നിഷ്‌ക്രിയം, ആപ്പ് പരിശോധിക്കൂ"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"കണ്ടെത്തിയില്ല"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"നിയന്ത്രണം ലഭ്യമല്ല"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 99913ca83ce5..4b2017376ad8 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Энд тоглуулахын тулд <xliff:g id="DEVICENAME">%1$s</xliff:g>-д ойртоно уу"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> дээр тоглуулж байна"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Алдаа гарлаа. Дахин оролдоно уу."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> ажиллаж байна"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Идэвхгүй байна, аппыг шалгана уу"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Олдсонгүй"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Хяналт боломжгүй байна"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 331bb318c70c..1cea901a545e 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"येथे प्ले करण्यासाठी <xliff:g id="DEVICENAME">%1$s</xliff:g> च्या जवळ जा"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> वर प्ले केला जात आहे"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"काहीतरी चूक झाली. पुन्हा प्रयत्न करा."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> रन होत आहे"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"निष्क्रिय, ॲप तपासा"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"आढळले नाही"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"नियंत्रण उपलब्ध नाही"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 894c2e903c6c..1b70a725c26a 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Dekatkan dengan <xliff:g id="DEVICENAME">%1$s</xliff:g> untuk bermain di sini"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Dimainkan pada <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Kesilapan telah berlaku. Cuba lagi."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> sedang dijalankan"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Tidak aktif, semak apl"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Tidak ditemukan"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Kawalan tidak tersedia"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index a66b2144ddef..63b61392bac8 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"ဤနေရာတွင်ဖွင့်ရန် <xliff:g id="DEVICENAME">%1$s</xliff:g> အနီးသို့တိုးပါ"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> တွင် ဖွင့်နေသည်"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"တစ်ခုခုမှားသွားသည်။ ထပ်စမ်းကြည့်ပါ။"</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> ပွင့်နေပါသည်"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"ရပ်နေသည်၊ အက်ပ်ကို စစ်ဆေးပါ"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"မတွေ့ပါ"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"ထိန်းချုပ်မှု မရနိုင်ပါ"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 725c2d46c15b..3df71e2dce1d 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Flytt deg nærmere <xliff:g id="DEVICENAME">%1$s</xliff:g> for å spille av her"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Spilles av på <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Noe gikk galt. Prøv på nytt."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> kjører"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inaktiv. Sjekk appen"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Ikke funnet"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrollen er utilgjengelig"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index a18cae414c8c..376207830cfc 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"तपाईं यहाँ प्ले गर्न चाहनुहुन्छ भने आफ्नो डिभाइसलाई <xliff:g id="DEVICENAME">%1$s</xliff:g> नजिकै लैजानुहोस्"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> मा प्ले गरिँदै छ"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"केही चिज गडबड भयो। फेरि प्रयास गर्नुहोस्।"</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> चलिरहेको छ"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"निष्क्रिय छ, एप जाँच गर्नु…"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"फेला परेन"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"नियन्त्रण उपलब्ध छैन"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 48fc30f5378e..f926af950478 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Ga dichter bij <xliff:g id="DEVICENAME">%1$s</xliff:g> staan om hier af te spelen"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Afspelen op <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Er is iets misgegaan. Probeer het opnieuw."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> is actief"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inactief, check de app"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Niet gevonden"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Beheeroptie niet beschikbaar"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 589aa0aef5a5..2fa333b8fee0 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"ଏଠାରେ ଚଲାଇବା ପାଇଁ <xliff:g id="DEVICENAME">%1$s</xliff:g>ର ପାଖକୁ ମୁଭ କରନ୍ତୁ"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g>ରେ ଚାଲୁଛି"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"କିଛି ତ୍ରୁଟି ହୋଇଛି। ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> ଚାଲୁଛି"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"ନିଷ୍କ୍ରିୟ ଅଛି, ଆପ ଯାଞ୍ଚ କରନ୍ତୁ"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"ମିଳିଲା ନାହିଁ"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"ନିୟନ୍ତ୍ରଣ ଉପଲବ୍ଧ ନାହିଁ"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index dd6070661c0a..7104d4a952b2 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"ਇੱਥੇ ਚਲਾਉਣ ਲਈ <xliff:g id="DEVICENAME">%1$s</xliff:g> ਦੇ ਨੇੜੇ ਜਾਓ"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> \'ਤੇ ਚਲਾਇਆ ਜਾ ਰਿਹਾ ਹੈ"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"ਕੋਈ ਗੜਬੜ ਹੋ ਗਈ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਚੱਲ ਰਿਹਾ ਹੈ"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"ਅਕਿਰਿਆਸ਼ੀਲ, ਐਪ ਦੀ ਜਾਂਚ ਕਰੋ"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"ਨਹੀਂ ਮਿਲਿਆ"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"ਕੰਟਰੋਲ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 66e5c1713740..891a9410f003 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -837,6 +837,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Zbliż do urządzenia <xliff:g id="DEVICENAME">%1$s</xliff:g>, aby na nim odtwarzać"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Odtwarzam na ekranie <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Coś poszło nie tak. Spróbuj ponownie."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> jest uruchomiona"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Nieaktywny, sprawdź aplikację"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Nie znaleziono"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Element jest niedostępny"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 22c5be686796..79b92b571c20 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -831,6 +831,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Aproxime-se do dispositivo <xliff:g id="DEVICENAME">%1$s</xliff:g> para abrir a mídia aqui"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Mídia aberta no dispositivo <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Algo deu errado. Tente novamente."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> está em execução"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inativo, verifique o app"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Não encontrado"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"O controle está indisponível"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index fcc75f684a63..a0e12a4969bd 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -831,6 +831,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Aproxime-se do dispositivo <xliff:g id="DEVICENAME">%1$s</xliff:g> para reproduzir aqui"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"A reproduzir no dispositivo <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Algo correu mal. Tente novamente."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> em execução"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inativa. Consulte a app."</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Não encontrado."</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"O controlo está indisponível"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 22c5be686796..79b92b571c20 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -831,6 +831,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Aproxime-se do dispositivo <xliff:g id="DEVICENAME">%1$s</xliff:g> para abrir a mídia aqui"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Mídia aberta no dispositivo <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Algo deu errado. Tente novamente."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> está em execução"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inativo, verifique o app"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Não encontrado"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"O controle está indisponível"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 78e7beb25359..1822c0fc4330 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -831,6 +831,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Apropie-te de <xliff:g id="DEVICENAME">%1$s</xliff:g> ca să redai acolo"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Se redă pe <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"A apărut o eroare. Încearcă din nou."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> rulează"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inactiv, verifică aplicația"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Nu s-a găsit"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Comanda este indisponibilă"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 2482cf969ab3..e2ba50826485 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -837,6 +837,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Для воспроизведения на этом устройстве подойдите ближе к другому (<xliff:g id="DEVICENAME">%1$s</xliff:g>)."</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Воспроизводится на устройстве \"<xliff:g id="DEVICENAME">%1$s</xliff:g>\"."</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Произошла ошибка. Повторите попытку."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" запущено"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Нет ответа. Проверьте приложение."</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Не найдено."</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Управление недоступно"</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 064841cbc307..ed7c752a9810 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"මෙහි ක්‍රීඩා කිරීමට <xliff:g id="DEVICENAME">%1$s</xliff:g> වෙත වඩා සමීප වන්න"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> හි වාදනය කරමින්"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"යම් දෙයක් වැරදිණි. නැවත උත්සාහ කරන්න."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> ධාවනය වේ"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"අක්‍රියයි, යෙදුම පරීක්ෂා කරන්න"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"හමු නොවිණි"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"පාලනය ලබා ගත නොහැකිය"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index b23b50aaa189..a8e1f9fa0d64 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -837,6 +837,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Ak chcete prehrávať v zariadení <xliff:g id="DEVICENAME">%1$s</xliff:g>, priblížte sa k nemu"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Prehráva sa v zariadení <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Niečo sa pokazilo. Skúste to znova."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"Aplikácia <xliff:g id="APP_NAME">%1$s</xliff:g> je spustená"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Neaktívne, preverte aplikáciu"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Nenájdené"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Ovládač nie je k dispozícii"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 8ec4eefb0169..06751596c3c9 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -837,6 +837,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Približajte napravi <xliff:g id="DEVICENAME">%1$s</xliff:g> za predvajanje v tej napravi"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Predvajanje v napravi <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Prišlo je do napake. Poskusite znova."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> se izvaja"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Neaktivno, poglejte aplikacijo"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Ni mogoče najti"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrolnik ni na voljo"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index c6a06bbe01e5..e84be5a93c7d 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Afrohu te <xliff:g id="DEVICENAME">%1$s</xliff:g> për ta luajtur këtu"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Po luhet në <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Ndodhi një gabim. Provo përsëri."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> po ekzekutohet"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Joaktive, kontrollo aplikacionin"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Nuk u gjet"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrolli është i padisponueshëm"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 0ff1663813a0..ac5ab327ebe6 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -831,6 +831,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Приближите се уређају <xliff:g id="DEVICENAME">%1$s</xliff:g> да бисте на њему пуштали"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Пушта се на уређају <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Дошло је до грешке. Пробајте поново."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"Апликација <xliff:g id="APP_NAME">%1$s</xliff:g> је покренута"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Неактивно. Видите апликацију"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Није пронађено"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Контрола није доступна"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 41560fdb2040..3b0819560cfe 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Flytta dig närmare <xliff:g id="DEVICENAME">%1$s</xliff:g> om du vill spela här"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Spelas upp på <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Något gick fel. Försök igen."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> körs"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inaktiv, kolla appen"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Hittades inte"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Styrning är inte tillgänglig"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 0b185166344c..ab27d8608fa1 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Sogeza karibu na <xliff:g id="DEVICENAME">%1$s</xliff:g> ili kucheza hapa"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Inacheza kwenye <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Hitilafu fulani imetokea. Jaribu tena."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> inatumika"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Haitumiki, angalia programu"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Hakipatikani"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Kidhibiti hakipatikani"</string>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 0ca9f5c2e67b..0048235d8420 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"இங்கு பிளே செய்ய உங்கள் சாதனத்தை <xliff:g id="DEVICENAME">%1$s</xliff:g> சாதனத்திற்கு அருகில் நகர்த்துங்கள்"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> சாதனத்தில் பிளே ஆகிறது"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"ஏதோ தவறாகிவிட்டது. மீண்டும் முயலவும்."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> இயங்கிக் கொண்டிருக்கிறது"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"செயலில் இல்லை , சரிபார்க்கவும்"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"இல்லை"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"கட்டுப்பாடு இல்லை"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 21edccd5e76c..d2af3d618ad9 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"ఇక్కడ ప్లే చేయడానికి <xliff:g id="DEVICENAME">%1$s</xliff:g>కి దగ్గరగా వెళ్లండి"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g>లో ప్లే అవుతోంది"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"ఏదో తప్పు జరిగింది. మళ్లీ ట్రై చేయండి."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> రన్ అవుతోంది"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"ఇన్‌యాక్టివ్, యాప్ చెక్ చేయండి"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"కనుగొనబడలేదు"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"కంట్రోల్ అందుబాటులో లేదు"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 21203179080e..08afe13aee57 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"ขยับไปใกล้ <xliff:g id="DEVICENAME">%1$s</xliff:g> มากขึ้นเพื่อเล่นที่นี่"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"กำลังเล่นใน <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"เกิดข้อผิดพลาด โปรดลองอีกครั้ง"</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> กำลังทำงาน"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"ไม่มีการใช้งาน โปรดตรวจสอบแอป"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"ไม่พบ"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"ใช้การควบคุมไม่ได้"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 6ed62f3e86ef..1c88061a2135 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Lumapit sa <xliff:g id="DEVICENAME">%1$s</xliff:g> para mag-play rito"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Nagpe-play sa <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Nagkaproblema. Subukan ulit."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"Tumatakbo ang <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Hindi aktibo, tingnan ang app"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Hindi nahanap"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Hindi available ang kontrol"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index c99caeaf600b..a0c4e378e494 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Burada oynatmak için <xliff:g id="DEVICENAME">%1$s</xliff:g> cihazına yaklaşın"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> cihazında oynatılıyor"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Bir sorun oldu. Tekrar deneyin."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> çalışıyor"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Devre dışı, uygulamaya bakın"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Bulunamadı"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrol kullanılamıyor"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 53b09091a5ce..7644e622a2df 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -837,6 +837,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Наблизьтеся до пристрою <xliff:g id="DEVICENAME">%1$s</xliff:g>, щоб відтворити медіафайли на ньому"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Відтворюється на пристрої <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Сталася помилка. Повторіть спробу."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> працює"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Неактивно, перейдіть у додаток"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Не знайдено"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Елемент керування недоступний"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 81640392abd7..f345c526a020 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"یہاں چلانے کے ليے <xliff:g id="DEVICENAME">%1$s</xliff:g> کے قریب جائیں"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> پر چل رہا ہے"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"کچھ غلط ہوگیا۔ پھر کوشش کریں۔"</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> چل رہی ہے"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"غیر فعال، ایپ چیک کریں"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"نہیں ملا"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"کنٹرول دستیاب نہیں ہے"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index b115cfd36778..d5e55106e149 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Bu yerda ijro qilish uchun <xliff:g id="DEVICENAME">%1$s</xliff:g>qurilmasiga yaqinlashtiring"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> qurilmasida ijro qilinmoqda"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Xatolik yuz berdi. Qayta urining."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> ishlamoqda"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Nofaol. Ilovani tekshiring"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Topilmadi"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Boshqarish imkonsiz"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index d57c702a2027..f92a78ad7234 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Di chuyển đến gần <xliff:g id="DEVICENAME">%1$s</xliff:g> hơn để phát tại đây"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Đang phát trên <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Đã xảy ra lỗi. Hãy thử lại."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"<xliff:g id="APP_NAME">%1$s</xliff:g> đang chạy"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Không hoạt động, hãy kiểm tra ứng dụng"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Không tìm thấy"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Không có chức năng điều khiển"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index e2cc98e87495..1d124fb487ef 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"若要在此设备上播放,请靠近“<xliff:g id="DEVICENAME">%1$s</xliff:g>”"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"正在“<xliff:g id="DEVICENAME">%1$s</xliff:g>”上播放"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"出了点问题,请重试。"</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”正在运行"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"无效,请检查应用"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"未找到"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"控件不可用"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 9877835e11c7..564dced77e76 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"如要在此裝置上播放,請靠近「<xliff:g id="DEVICENAME">%1$s</xliff:g>」"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"正在「<xliff:g id="DEVICENAME">%1$s</xliff:g>」上播放"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"發生錯誤,請再試一次。"</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」執行中"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"已停用,請檢查應用程式"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"找不到"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"無法使用控制功能"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index c1bb69a7b68a..019cafceeab0 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"如要在這部裝置上播放,請移到更靠近「<xliff:g id="DEVICENAME">%1$s</xliff:g>」的位置"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"正在「<xliff:g id="DEVICENAME">%1$s</xliff:g>」上播放"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"發生錯誤,請再試一次。"</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」執行中"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"無效,請查看應用程式"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"找不到控制項"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"無法使用控制項"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 3e83354faa5c..1f78b3216fd2 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -825,6 +825,7 @@
<string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Sondela eduze ne-<xliff:g id="DEVICENAME">%1$s</xliff:g> ukuze udlale lapha"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Idlala ku-<xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Kukhona okungahambanga kahle. Zama futhi."</string>
+ <string name="controls_media_empty_title" msgid="8296102892421573325">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> iyasebenza"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Akusebenzi, hlola uhlelo lokusebenza"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Ayitholakali"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Ukulawula akutholakali"</string>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index af8d7ed22ed3..b0fcfcdc2f6b 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2230,6 +2230,8 @@
<string name="controls_media_smartspace_rec_item_description">Play <xliff:g id="song_name" example="Daily mix">%1$s</xliff:g> by <xliff:g id="artist_name" example="Various artists">%2$s</xliff:g> from <xliff:g id="app_label" example="Spotify">%3$s</xliff:g></string>
<!-- Description for Smartspace recommendation's media item which doesn't have artist info, including information for the media's title and the source app [CHAR LIMIT=NONE]-->
<string name="controls_media_smartspace_rec_item_no_artist_description">Play <xliff:g id="song_name" example="Daily mix">%1$s</xliff:g> from <xliff:g id="app_label" example="Spotify">%2$s</xliff:g></string>
+ <!-- Placeholder title to inform user that an app has posted media controls [CHAR_LIMIT=NONE] -->
+ <string name="controls_media_empty_title"><xliff:g id="app_name" example="Foo Music App">%1$s</xliff:g> is running</string>
<!--- ****** Media tap-to-transfer ****** -->
<!-- Text for a button to undo the media transfer. [CHAR LIMIT=20] -->
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index 0309d212e03f..c5fd4c1c4b90 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -62,6 +62,7 @@ import com.android.systemui.log.SessionTracker;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.shared.system.SysUiStatsLog;
import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.UserSwitcherController;
import com.android.systemui.util.ViewController;
@@ -250,6 +251,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
showPrimarySecurityScreen(false);
}
};
+ private final DeviceProvisionedController mDeviceProvisionedController;
private KeyguardSecurityContainerController(KeyguardSecurityContainer view,
AdminSecondaryLockScreenController.Factory adminSecondaryLockScreenControllerFactory,
@@ -267,7 +269,9 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
UserSwitcherController userSwitcherController,
FeatureFlags featureFlags,
GlobalSettings globalSettings,
- SessionTracker sessionTracker) {
+ SessionTracker sessionTracker,
+ DeviceProvisionedController deviceProvisionedController
+ ) {
super(view);
mLockPatternUtils = lockPatternUtils;
mUpdateMonitor = keyguardUpdateMonitor;
@@ -287,6 +291,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
mFeatureFlags = featureFlags;
mGlobalSettings = globalSettings;
mSessionTracker = sessionTracker;
+ mDeviceProvisionedController = deviceProvisionedController;
}
@Override
@@ -469,8 +474,11 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
case SimPuk:
// Shortcut for SIM PIN/PUK to go to directly to user's security screen or home
SecurityMode securityMode = mSecurityModel.getSecurityMode(targetUserId);
- if (securityMode == SecurityMode.None || mLockPatternUtils.isLockScreenDisabled(
- KeyguardUpdateMonitor.getCurrentUser())) {
+ boolean isLockscreenDisabled = mLockPatternUtils.isLockScreenDisabled(
+ KeyguardUpdateMonitor.getCurrentUser())
+ || !mDeviceProvisionedController.isUserSetup(targetUserId);
+
+ if (securityMode == SecurityMode.None && isLockscreenDisabled) {
finish = true;
eventSubtype = BOUNCER_DISMISS_SIM;
uiEvent = BouncerUiEvent.BOUNCER_DISMISS_SIM;
@@ -676,6 +684,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
private final FeatureFlags mFeatureFlags;
private final UserSwitcherController mUserSwitcherController;
private final SessionTracker mSessionTracker;
+ private final DeviceProvisionedController mDeviceProvisionedController;
@Inject
Factory(KeyguardSecurityContainer view,
@@ -694,7 +703,8 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
UserSwitcherController userSwitcherController,
FeatureFlags featureFlags,
GlobalSettings globalSettings,
- SessionTracker sessionTracker) {
+ SessionTracker sessionTracker,
+ DeviceProvisionedController deviceProvisionedController) {
mView = view;
mAdminSecondaryLockScreenControllerFactory = adminSecondaryLockScreenControllerFactory;
mLockPatternUtils = lockPatternUtils;
@@ -711,6 +721,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
mGlobalSettings = globalSettings;
mUserSwitcherController = userSwitcherController;
mSessionTracker = sessionTracker;
+ mDeviceProvisionedController = deviceProvisionedController;
}
public KeyguardSecurityContainerController create(
@@ -720,7 +731,8 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
mKeyguardUpdateMonitor, mKeyguardSecurityModel, mMetricsLogger, mUiEventLogger,
mKeyguardStateController, securityCallback, mSecurityViewFlipperController,
mConfigurationController, mFalsingCollector, mFalsingManager,
- mUserSwitcherController, mFeatureFlags, mGlobalSettings, mSessionTracker);
+ mUserSwitcherController, mFeatureFlags, mGlobalSettings, mSessionTracker,
+ mDeviceProvisionedController);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
index 3eb58bba1ca4..ec76f433b23b 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
@@ -38,6 +38,7 @@ import androidx.core.view.accessibility.AccessibilityNodeInfoCompat
import androidx.recyclerview.widget.RecyclerView
import com.android.systemui.R
import com.android.systemui.controls.ControlInterface
+import com.android.systemui.controls.ui.CanUseIconPredicate
import com.android.systemui.controls.ui.RenderInfo
private typealias ModelFavoriteChanger = (String, Boolean) -> Unit
@@ -51,7 +52,8 @@ private typealias ModelFavoriteChanger = (String, Boolean) -> Unit
* @property elevation elevation of each control view
*/
class ControlAdapter(
- private val elevation: Float
+ private val elevation: Float,
+ private val currentUserId: Int,
) : RecyclerView.Adapter<Holder>() {
companion object {
@@ -107,7 +109,8 @@ class ControlAdapter(
background = parent.context.getDrawable(
R.drawable.control_background_ripple)
},
- model?.moveHelper // Indicates that position information is needed
+ currentUserId,
+ model?.moveHelper, // Indicates that position information is needed
) { id, favorite ->
model?.changeFavoriteStatus(id, favorite)
}
@@ -212,8 +215,9 @@ private class ZoneHolder(view: View) : Holder(view) {
*/
internal class ControlHolder(
view: View,
+ currentUserId: Int,
val moveHelper: ControlsModel.MoveHelper?,
- val favoriteCallback: ModelFavoriteChanger
+ val favoriteCallback: ModelFavoriteChanger,
) : Holder(view) {
private val favoriteStateDescription =
itemView.context.getString(R.string.accessibility_control_favorite)
@@ -228,6 +232,7 @@ internal class ControlHolder(
visibility = View.VISIBLE
}
+ private val canUseIconPredicate = CanUseIconPredicate(currentUserId)
private val accessibilityDelegate = ControlHolderAccessibilityDelegate(
this::stateDescription,
this::getLayoutPosition,
@@ -287,7 +292,9 @@ internal class ControlHolder(
val fg = context.getResources().getColorStateList(ri.foreground, context.getTheme())
icon.imageTintList = null
- ci.customIcon?.let {
+ ci.customIcon
+ ?.takeIf(canUseIconPredicate)
+ ?.let {
icon.setImageIcon(it)
} ?: run {
icon.setImageDrawable(ri.icon)
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt
index f611c3ef966d..d6cbb02712c2 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt
@@ -180,7 +180,7 @@ class ControlsEditingActivity @Inject constructor(
val elevation = resources.getFloat(R.dimen.control_card_elevation)
val recyclerView = requireViewById<RecyclerView>(R.id.list)
recyclerView.alpha = 0.0f
- val adapter = ControlAdapter(elevation).apply {
+ val adapter = ControlAdapter(elevation, currentUserTracker.currentUserId).apply {
registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
var hasAnimated = false
override fun onChanged() {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
index dca52a9678b9..a5cc07885a14 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
@@ -164,7 +164,7 @@ class ControlsFavoritingActivity @Inject constructor(
}
executor.execute {
- structurePager.adapter = StructureAdapter(listOfStructures)
+ structurePager.adapter = StructureAdapter(listOfStructures, currentUserTracker.currentUserId)
structurePager.setCurrentItem(structureIndex)
if (error) {
statusText.text = resources.getString(R.string.controls_favorite_load_error,
@@ -210,7 +210,7 @@ class ControlsFavoritingActivity @Inject constructor(
structurePager.alpha = 0.0f
pageIndicator.alpha = 0.0f
structurePager.apply {
- adapter = StructureAdapter(emptyList())
+ adapter = StructureAdapter(emptyList(), currentUserTracker.currentUserId)
registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
override fun onPageSelected(position: Int) {
super.onPageSelected(position)
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/StructureAdapter.kt b/packages/SystemUI/src/com/android/systemui/controls/management/StructureAdapter.kt
index 747bcbe1c229..5977d379acde 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/StructureAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/StructureAdapter.kt
@@ -24,13 +24,15 @@ import androidx.recyclerview.widget.RecyclerView
import com.android.systemui.R
class StructureAdapter(
- private val models: List<StructureContainer>
+ private val models: List<StructureContainer>,
+ private val currentUserId: Int,
) : RecyclerView.Adapter<StructureAdapter.StructureHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, p1: Int): StructureHolder {
val layoutInflater = LayoutInflater.from(parent.context)
return StructureHolder(
- layoutInflater.inflate(R.layout.controls_structure_page, parent, false)
+ layoutInflater.inflate(R.layout.controls_structure_page, parent, false),
+ currentUserId,
)
}
@@ -40,7 +42,8 @@ class StructureAdapter(
holder.bind(models[index].model)
}
- class StructureHolder(view: View) : RecyclerView.ViewHolder(view) {
+ class StructureHolder(view: View, currentUserId: Int) :
+ RecyclerView.ViewHolder(view) {
private val recyclerView: RecyclerView
private val controlAdapter: ControlAdapter
@@ -48,7 +51,7 @@ class StructureAdapter(
init {
recyclerView = itemView.requireViewById<RecyclerView>(R.id.listAll)
val elevation = itemView.context.resources.getFloat(R.dimen.control_card_elevation)
- controlAdapter = ControlAdapter(elevation)
+ controlAdapter = ControlAdapter(elevation, currentUserId)
setUpRecyclerView()
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/CanUseIconPredicate.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/CanUseIconPredicate.kt
new file mode 100644
index 000000000000..61c21237144d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/CanUseIconPredicate.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.controls.ui
+
+import android.content.ContentProvider
+import android.graphics.drawable.Icon
+
+class CanUseIconPredicate(private val currentUserId: Int) : (Icon) -> Boolean {
+
+ override fun invoke(icon: Icon): Boolean =
+ if (icon.type == Icon.TYPE_URI || icon.type == Icon.TYPE_URI_ADAPTIVE_BITMAP) {
+ ContentProvider.getUserIdFromUri(icon.uri, currentUserId) == currentUserId
+ } else {
+ true
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
index 6a9aaf865251..931062865c64 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
@@ -68,7 +68,8 @@ class ControlViewHolder(
val bgExecutor: DelayableExecutor,
val controlActionCoordinator: ControlActionCoordinator,
val controlsMetricsLogger: ControlsMetricsLogger,
- val uid: Int
+ val uid: Int,
+ val currentUserId: Int,
) {
companion object {
@@ -85,29 +86,9 @@ class ControlViewHolder(
private val ATTR_DISABLED = intArrayOf(-android.R.attr.state_enabled)
const val MIN_LEVEL = 0
const val MAX_LEVEL = 10000
-
- fun findBehaviorClass(
- status: Int,
- template: ControlTemplate,
- deviceType: Int
- ): Supplier<out Behavior> {
- return when {
- status != Control.STATUS_OK -> Supplier { StatusBehavior() }
- template == ControlTemplate.NO_TEMPLATE -> Supplier { TouchBehavior() }
- template is ThumbnailTemplate -> Supplier { ThumbnailBehavior() }
-
- // Required for legacy support, or where cameras do not use the new template
- deviceType == DeviceTypes.TYPE_CAMERA -> Supplier { TouchBehavior() }
- template is ToggleTemplate -> Supplier { ToggleBehavior() }
- template is StatelessTemplate -> Supplier { TouchBehavior() }
- template is ToggleRangeTemplate -> Supplier { ToggleRangeBehavior() }
- template is RangeTemplate -> Supplier { ToggleRangeBehavior() }
- template is TemperatureControlTemplate -> Supplier { TemperatureControlBehavior() }
- else -> Supplier { DefaultBehavior() }
- }
- }
}
+ private val canUseIconPredicate = CanUseIconPredicate(currentUserId)
private val toggleBackgroundIntensity: Float = layout.context.resources
.getFraction(R.fraction.controls_toggle_bg_intensity, 1, 1)
private var stateAnimator: ValueAnimator? = null
@@ -147,6 +128,27 @@ class ControlViewHolder(
status.setSelected(true)
}
+ fun findBehaviorClass(
+ status: Int,
+ template: ControlTemplate,
+ deviceType: Int
+ ): Supplier<out Behavior> {
+ return when {
+ status != Control.STATUS_OK -> Supplier { StatusBehavior() }
+ template == ControlTemplate.NO_TEMPLATE -> Supplier { TouchBehavior() }
+ template is ThumbnailTemplate -> Supplier { ThumbnailBehavior(currentUserId) }
+
+ // Required for legacy support, or where cameras do not use the new template
+ deviceType == DeviceTypes.TYPE_CAMERA -> Supplier { TouchBehavior() }
+ template is ToggleTemplate -> Supplier { ToggleBehavior() }
+ template is StatelessTemplate -> Supplier { TouchBehavior() }
+ template is ToggleRangeTemplate -> Supplier { ToggleRangeBehavior() }
+ template is RangeTemplate -> Supplier { ToggleRangeBehavior() }
+ template is TemperatureControlTemplate -> Supplier { TemperatureControlBehavior() }
+ else -> Supplier { DefaultBehavior() }
+ }
+ }
+
fun bindData(cws: ControlWithState, isLocked: Boolean) {
// If an interaction is in progress, the update may visually interfere with the action the
// action the user wants to make. Don't apply the update, and instead assume a new update
@@ -473,7 +475,9 @@ class ControlViewHolder(
status.setTextColor(color)
- control?.getCustomIcon()?.let {
+ control?.customIcon
+ ?.takeIf(canUseIconPredicate)
+ ?.let {
icon.setImageIcon(it)
icon.imageTintList = it.tintList
} ?: run {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
index 1268250137b8..aa390d9af7e8 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
@@ -411,7 +411,8 @@ class ControlsUiControllerImpl @Inject constructor (
bgExecutor,
controlActionCoordinator,
controlsMetricsLogger,
- selected.uid
+ selected.uid,
+ controlsController.get().currentUserId,
)
cvh.bindData(it, false /* isLocked, will be ignored on initial load */)
controlViewsById.put(key, cvh)
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/TemperatureControlBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/TemperatureControlBehavior.kt
index a7dc09bb17e5..39d69704d817 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/TemperatureControlBehavior.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/TemperatureControlBehavior.kt
@@ -63,7 +63,7 @@ class TemperatureControlBehavior : Behavior {
// interactions (touch, range)
subBehavior = cvh.bindBehavior(
subBehavior,
- ControlViewHolder.findBehaviorClass(
+ cvh.findBehaviorClass(
control.status,
subTemplate,
control.deviceType
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ThumbnailBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ThumbnailBehavior.kt
index c2168aa8d9d9..0b57e792f9f7 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ThumbnailBehavior.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ThumbnailBehavior.kt
@@ -33,7 +33,7 @@ import com.android.systemui.controls.ui.ControlViewHolder.Companion.MIN_LEVEL
* Supports display of static images on the background of the tile. When marked active, the title
* and subtitle will not be visible. To be used with {@link Thumbnailtemplate} only.
*/
-class ThumbnailBehavior : Behavior {
+class ThumbnailBehavior(currentUserId: Int) : Behavior {
lateinit var template: ThumbnailTemplate
lateinit var control: Control
lateinit var cvh: ControlViewHolder
@@ -42,6 +42,7 @@ class ThumbnailBehavior : Behavior {
private var shadowRadius: Float = 0f
private var shadowColor: Int = 0
+ private val canUseIconPredicate = CanUseIconPredicate(currentUserId)
private val enabled: Boolean
get() = template.isActive()
@@ -80,11 +81,16 @@ class ThumbnailBehavior : Behavior {
cvh.status.setShadowLayer(shadowOffsetX, shadowOffsetY, shadowRadius, shadowColor)
cvh.bgExecutor.execute {
- val drawable = template.getThumbnail().loadDrawable(cvh.context)
+ val drawable = template.thumbnail
+ ?.takeIf(canUseIconPredicate)
+ ?.loadDrawable(cvh.context)
cvh.uiExecutor.execute {
val radius = cvh.context.getResources()
.getDimensionPixelSize(R.dimen.control_corner_radius).toFloat()
- clipLayer.setDrawable(CornerDrawable(drawable, radius))
+ // TODO(b/290037843): Add a placeholder
+ drawable?.let {
+ clipLayer.drawable = CornerDrawable(it, radius)
+ }
clipLayer.setColorFilter(BlendModeColorFilter(cvh.context.resources
.getColor(R.color.control_thumbnail_tint), BlendMode.LUMINOSITY))
cvh.applyRenderInfo(enabled, colorOffset)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 374522af38fa..e13e42fbe3ad 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -1385,9 +1385,9 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable,
final ContentResolver cr = mContext.getContentResolver();
// From SecuritySettings
- final long lockAfterTimeout = Settings.Secure.getInt(cr,
+ final long lockAfterTimeout = Settings.Secure.getIntForUser(cr,
Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT,
- KEYGUARD_LOCK_AFTER_DELAY_DEFAULT);
+ KEYGUARD_LOCK_AFTER_DELAY_DEFAULT, userId);
// From DevicePolicyAdmin
final long policyTimeout = mLockPatternUtils.getDevicePolicyManager()
@@ -1399,8 +1399,8 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable,
timeout = lockAfterTimeout;
} else {
// From DisplaySettings
- long displayTimeout = Settings.System.getInt(cr, SCREEN_OFF_TIMEOUT,
- KEYGUARD_DISPLAY_TIMEOUT_DELAY_DEFAULT);
+ long displayTimeout = Settings.System.getIntForUser(cr, SCREEN_OFF_TIMEOUT,
+ KEYGUARD_DISPLAY_TIMEOUT_DELAY_DEFAULT, userId);
// policy in effect. Make sure we don't go beyond policy limit.
displayTimeout = Math.max(displayTimeout, 0); // ignore negative values
@@ -2241,7 +2241,10 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable,
private void playSound(int soundId) {
if (soundId == 0) return;
final ContentResolver cr = mContext.getContentResolver();
- if (Settings.System.getInt(cr, Settings.System.LOCKSCREEN_SOUNDS_ENABLED, 1) == 1) {
+ int lockscreenSoundsEnabled = Settings.System.getIntForUser(cr,
+ Settings.System.LOCKSCREEN_SOUNDS_ENABLED, 1,
+ KeyguardUpdateMonitor.getCurrentUser());
+ if (lockscreenSoundsEnabled == 1) {
mLockSounds.stop(mLockSoundStreamId);
// Init mAudioManager
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
index 6a69d427929e..4c2336eeb22c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
@@ -658,12 +658,16 @@ class MediaDataManager(
// Song name
var song: CharSequence? = metadata?.getString(MediaMetadata.METADATA_KEY_DISPLAY_TITLE)
- if (song == null) {
+ if (song.isNullOrBlank()) {
song = metadata?.getString(MediaMetadata.METADATA_KEY_TITLE)
}
- if (song == null) {
+ if (song.isNullOrBlank()) {
song = HybridGroupManager.resolveTitle(notif)
}
+ if (song.isNullOrBlank()) {
+ // For apps that don't include a title, add a placeholder
+ song = context.getString(R.string.controls_media_empty_title, app)
+ }
// Artist name
var artist: CharSequence? = metadata?.getString(MediaMetadata.METADATA_KEY_ARTIST)
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt b/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt
index cc06b6c67879..bad87de438e5 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt
@@ -101,9 +101,16 @@ class MediaResumeListener @Inject constructor(
Log.e(TAG, "Error getting package information", e)
}
- Log.d(TAG, "Adding resume controls $desc")
- mediaDataManager.addResumptionControls(currentUserId, desc, resumeAction, token,
- appName.toString(), appIntent, component.packageName)
+ Log.d(TAG, "Adding resume controls for ${browser.userId}: $desc")
+ mediaDataManager.addResumptionControls(
+ browser.userId,
+ desc,
+ resumeAction,
+ token,
+ appName.toString(),
+ appIntent,
+ component.packageName
+ )
}
}
@@ -158,7 +165,11 @@ class MediaResumeListener @Inject constructor(
}
resumeComponents.add(component to lastPlayed)
}
- Log.d(TAG, "loaded resume components ${resumeComponents.toArray().contentToString()}")
+ Log.d(
+ TAG,
+ "loaded resume components for $currentUserId: " +
+ "${resumeComponents.toArray().contentToString()}"
+ )
if (needsUpdate) {
// Save any missing times that we had to fill in
@@ -174,11 +185,21 @@ class MediaResumeListener @Inject constructor(
return
}
+ val pm = context.packageManager
val now = systemClock.currentTimeMillis()
resumeComponents.forEach {
if (now.minus(it.second) <= RESUME_MEDIA_TIMEOUT) {
- val browser = mediaBrowserFactory.create(mediaBrowserCallback, it.first)
- browser.findRecentMedia()
+ // Verify that the service exists for this user
+ val intent = Intent(MediaBrowserService.SERVICE_INTERFACE)
+ intent.component = it.first
+ val inf = pm.resolveServiceAsUser(intent, 0, currentUserId)
+ if (inf != null) {
+ val browser =
+ mediaBrowserFactory.create(mediaBrowserCallback, it.first, currentUserId)
+ browser.findRecentMedia()
+ } else {
+ Log.d(TAG, "User $currentUserId does not have component ${it.first}")
+ }
}
}
}
@@ -202,7 +223,7 @@ class MediaResumeListener @Inject constructor(
Log.d(TAG, "Checking for service component for " + data.packageName)
val pm = context.packageManager
val serviceIntent = Intent(MediaBrowserService.SERVICE_INTERFACE)
- val resumeInfo = pm.queryIntentServices(serviceIntent, 0)
+ val resumeInfo = pm.queryIntentServicesAsUser(serviceIntent, 0, currentUserId)
val inf = resumeInfo?.filter {
it.serviceInfo.packageName == data.packageName
@@ -244,13 +265,18 @@ class MediaResumeListener @Inject constructor(
browser: ResumeMediaBrowser
) {
// Since this is a test, just save the component for later
- Log.d(TAG, "Can get resumable media from $componentName")
+ Log.d(
+ TAG,
+ "Can get resumable media for ${browser.userId} from $componentName"
+ )
mediaDataManager.setResumeAction(key, getResumeAction(componentName))
updateResumptionList(componentName)
mediaBrowser = null
}
},
- componentName)
+ componentName,
+ currentUserId
+ )
mediaBrowser?.testConnection()
}
@@ -290,7 +316,7 @@ class MediaResumeListener @Inject constructor(
*/
private fun getResumeAction(componentName: ComponentName): Runnable {
return Runnable {
- mediaBrowser = mediaBrowserFactory.create(null, componentName)
+ mediaBrowser = mediaBrowserFactory.create(null, componentName, currentUserId)
mediaBrowser?.restart()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/ResumeMediaBrowser.java b/packages/SystemUI/src/com/android/systemui/media/ResumeMediaBrowser.java
index 40a5653a15a0..018697f772e0 100644
--- a/packages/SystemUI/src/com/android/systemui/media/ResumeMediaBrowser.java
+++ b/packages/SystemUI/src/com/android/systemui/media/ResumeMediaBrowser.java
@@ -17,6 +17,7 @@
package com.android.systemui.media;
import android.annotation.Nullable;
+import android.annotation.UserIdInt;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
@@ -53,6 +54,7 @@ public class ResumeMediaBrowser {
private final ResumeMediaBrowserLogger mLogger;
private final ComponentName mComponentName;
private final MediaController.Callback mMediaControllerCallback = new SessionDestroyCallback();
+ @UserIdInt private final int mUserId;
private MediaBrowser mMediaBrowser;
@Nullable private MediaController mMediaController;
@@ -62,18 +64,21 @@ public class ResumeMediaBrowser {
* @param context the context
* @param callback used to report media items found
* @param componentName Component name of the MediaBrowserService this browser will connect to
+ * @param userId ID of the current user
*/
public ResumeMediaBrowser(
Context context,
@Nullable Callback callback,
ComponentName componentName,
MediaBrowserFactory browserFactory,
- ResumeMediaBrowserLogger logger) {
+ ResumeMediaBrowserLogger logger,
+ @UserIdInt int userId) {
mContext = context;
mCallback = callback;
mComponentName = componentName;
mBrowserFactory = browserFactory;
mLogger = logger;
+ mUserId = userId;
}
/**
@@ -276,6 +281,14 @@ public class ResumeMediaBrowser {
}
/**
+ * Get the ID of the user associated with this broswer
+ * @return the user ID
+ */
+ public @UserIdInt int getUserId() {
+ return mUserId;
+ }
+
+ /**
* Get the media session token
* @return the token, or null if the MediaBrowser is null or disconnected
*/
diff --git a/packages/SystemUI/src/com/android/systemui/media/ResumeMediaBrowserFactory.java b/packages/SystemUI/src/com/android/systemui/media/ResumeMediaBrowserFactory.java
index 3d1380b6bd24..fca0ab7e5316 100644
--- a/packages/SystemUI/src/com/android/systemui/media/ResumeMediaBrowserFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/media/ResumeMediaBrowserFactory.java
@@ -16,6 +16,7 @@
package com.android.systemui.media;
+import android.annotation.UserIdInt;
import android.content.ComponentName;
import android.content.Context;
@@ -42,10 +43,12 @@ public class ResumeMediaBrowserFactory {
*
* @param callback will be called on connection or error, and addTrack when media item found
* @param componentName component to browse
+ * @param userId ID of the current user
* @return
*/
public ResumeMediaBrowser create(ResumeMediaBrowser.Callback callback,
- ComponentName componentName) {
- return new ResumeMediaBrowser(mContext, callback, componentName, mBrowserFactory, mLogger);
+ ComponentName componentName, @UserIdInt int userId) {
+ return new ResumeMediaBrowser(mContext, callback, componentName, mBrowserFactory, mLogger,
+ userId);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
index 50ee1f7ba97a..f4a257fdd3ec 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
@@ -135,7 +135,12 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> {
// Since Quick Share target recommendation does not rely on image URL, it is
// queried and surfaced before image compress/export. Action intent would not be
// used, because it does not contain image URL.
- queryQuickShareAction(image, user);
+ Notification.Action quickShare =
+ queryQuickShareAction(mScreenshotId, image, user, null);
+ if (quickShare != null) {
+ mQuickShareData.quickShareAction = quickShare;
+ mParams.mQuickShareActionsReadyListener.onActionsReady(mQuickShareData);
+ }
}
// Call synchronously here since already on a background thread.
@@ -168,8 +173,9 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> {
mImageData.shareTransition = createShareAction(mContext, mContext.getResources(), uri);
mImageData.editTransition = createEditAction(mContext, mContext.getResources(), uri);
mImageData.deleteAction = createDeleteAction(mContext, mContext.getResources(), uri);
- mImageData.quickShareAction = createQuickShareAction(mContext,
- mQuickShareData.quickShareAction, uri);
+ mImageData.quickShareAction = createQuickShareAction(
+ mQuickShareData.quickShareAction, mScreenshotId, uri, mImageTime, image,
+ user);
mParams.mActionsReadyListener.onActionsReady(mImageData);
if (DEBUG_CALLBACK) {
@@ -409,59 +415,73 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> {
}
/**
- * Populate image uri into intent of Quick Share action.
+ * Wrap the quickshare intent and populate the fillin intent with the URI
*/
@VisibleForTesting
- private Notification.Action createQuickShareAction(Context context, Notification.Action action,
- Uri uri) {
- if (action == null) {
+ Notification.Action createQuickShareAction(
+ Notification.Action quickShare, String screenshotId, Uri uri, long imageTime,
+ Bitmap image, UserHandle user) {
+ if (quickShare == null) {
return null;
+ } else if (quickShare.actionIntent.isImmutable()) {
+ Notification.Action quickShareWithUri =
+ queryQuickShareAction(screenshotId, image, user, uri);
+ if (quickShareWithUri == null
+ || !quickShareWithUri.title.toString().contentEquals(quickShare.title)) {
+ return null;
+ }
+ quickShare = quickShareWithUri;
}
- // Populate image URI into Quick Share chip intent
- Intent sharingIntent = action.actionIntent.getIntent();
- sharingIntent.setType("image/png");
- sharingIntent.putExtra(Intent.EXTRA_STREAM, uri);
- String subjectDate = DateFormat.getDateTimeInstance().format(new Date(mImageTime));
+
+ Intent wrappedIntent = new Intent(mContext, SmartActionsReceiver.class)
+ .putExtra(ScreenshotController.EXTRA_ACTION_INTENT, quickShare.actionIntent)
+ .putExtra(ScreenshotController.EXTRA_ACTION_INTENT_FILLIN,
+ createFillInIntent(uri, imageTime))
+ .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+ Bundle extras = quickShare.getExtras();
+ String actionType = extras.getString(
+ ScreenshotNotificationSmartActionsProvider.ACTION_TYPE,
+ ScreenshotNotificationSmartActionsProvider.DEFAULT_ACTION_TYPE);
+ addIntentExtras(screenshotId, wrappedIntent, actionType, mSmartActionsEnabled);
+ PendingIntent broadcastIntent =
+ PendingIntent.getBroadcast(mContext, mRandom.nextInt(), wrappedIntent,
+ PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE);
+ return new Notification.Action.Builder(quickShare.getIcon(), quickShare.title,
+ broadcastIntent)
+ .setContextual(true)
+ .addExtras(extras)
+ .build();
+ }
+
+ private Intent createFillInIntent(Uri uri, long imageTime) {
+ Intent fillIn = new Intent();
+ fillIn.setType("image/png");
+ fillIn.putExtra(Intent.EXTRA_STREAM, uri);
+ String subjectDate = DateFormat.getDateTimeInstance().format(new Date(imageTime));
String subject = String.format(SCREENSHOT_SHARE_SUBJECT_TEMPLATE, subjectDate);
- sharingIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
+ fillIn.putExtra(Intent.EXTRA_SUBJECT, subject);
// Include URI in ClipData also, so that grantPermission picks it up.
// We don't use setData here because some apps interpret this as "to:".
- ClipData clipdata = new ClipData(new ClipDescription("content",
- new String[]{"image/png"}),
+ ClipData clipData = new ClipData(
+ new ClipDescription("content", new String[]{"image/png"}),
new ClipData.Item(uri));
- sharingIntent.setClipData(clipdata);
- sharingIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
- PendingIntent updatedPendingIntent = PendingIntent.getActivity(
- context, 0, sharingIntent,
- PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE);
-
- // Proxy smart actions through {@link SmartActionsReceiver} for logging smart actions.
- Bundle extras = action.getExtras();
- String actionType = extras.getString(
- ScreenshotNotificationSmartActionsProvider.ACTION_TYPE,
- ScreenshotNotificationSmartActionsProvider.DEFAULT_ACTION_TYPE);
- Intent intent = new Intent(context, SmartActionsReceiver.class)
- .putExtra(ScreenshotController.EXTRA_ACTION_INTENT, updatedPendingIntent)
- .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
- addIntentExtras(mScreenshotId, intent, actionType, mSmartActionsEnabled);
- PendingIntent broadcastIntent = PendingIntent.getBroadcast(context,
- mRandom.nextInt(),
- intent,
- PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE);
- return new Notification.Action.Builder(action.getIcon(), action.title,
- broadcastIntent).setContextual(true).addExtras(extras).build();
+ fillIn.setClipData(clipData);
+ fillIn.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ return fillIn;
}
/**
* Query and surface Quick Share chip if it is available. Action intent would not be used,
* because it does not contain image URL which would be populated in {@link
- * #createQuickShareAction(Context, Notification.Action, Uri)}
+ * #createQuickShareAction(Notification.Action, String, Uri, long, Bitmap, UserHandle)}
*/
- private void queryQuickShareAction(Bitmap image, UserHandle user) {
+
+ @VisibleForTesting
+ Notification.Action queryQuickShareAction(
+ String screenshotId, Bitmap image, UserHandle user, Uri uri) {
CompletableFuture<List<Notification.Action>> quickShareActionsFuture =
mScreenshotSmartActions.getSmartActionsFuture(
- mScreenshotId, null, image, mSmartActionsProvider,
- QUICK_SHARE_ACTION,
+ screenshotId, uri, image, mSmartActionsProvider, QUICK_SHARE_ACTION,
mSmartActionsEnabled, user);
int timeoutMs = DeviceConfig.getInt(
DeviceConfig.NAMESPACE_SYSTEMUI,
@@ -469,11 +489,11 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> {
500);
List<Notification.Action> quickShareActions =
mScreenshotSmartActions.getSmartActions(
- mScreenshotId, quickShareActionsFuture, timeoutMs,
+ screenshotId, quickShareActionsFuture, timeoutMs,
mSmartActionsProvider, QUICK_SHARE_ACTION);
if (!quickShareActions.isEmpty()) {
- mQuickShareData.quickShareAction = quickShareActions.get(0);
- mParams.mQuickShareActionsReadyListener.onActionsReady(mQuickShareData);
+ return quickShareActions.get(0);
}
+ return null;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
index c213f192291a..e3089f859601 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
@@ -234,6 +234,7 @@ public class ScreenshotController {
static final String EXTRA_SMART_ACTIONS_ENABLED = "android:smart_actions_enabled";
static final String EXTRA_OVERRIDE_TRANSITION = "android:screenshot_override_transition";
static final String EXTRA_ACTION_INTENT = "android:screenshot_action_intent";
+ static final String EXTRA_ACTION_INTENT_FILLIN = "android:screenshot_action_intent_fillin";
static final String SCREENSHOT_URI_ID = "android:screenshot_uri_id";
static final String EXTRA_CANCEL_NOTIFICATION = "android:screenshot_cancel_notification";
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/SmartActionsReceiver.java b/packages/SystemUI/src/com/android/systemui/screenshot/SmartActionsReceiver.java
index f703058f4a0f..ecc13ee747c8 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/SmartActionsReceiver.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/SmartActionsReceiver.java
@@ -18,6 +18,7 @@ package com.android.systemui.screenshot;
import static com.android.systemui.screenshot.LogConfig.DEBUG_ACTIONS;
import static com.android.systemui.screenshot.ScreenshotController.EXTRA_ACTION_INTENT;
+import static com.android.systemui.screenshot.ScreenshotController.EXTRA_ACTION_INTENT_FILLIN;
import static com.android.systemui.screenshot.ScreenshotController.EXTRA_ACTION_TYPE;
import static com.android.systemui.screenshot.ScreenshotController.EXTRA_ID;
@@ -46,7 +47,9 @@ public class SmartActionsReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
- PendingIntent pendingIntent = intent.getParcelableExtra(EXTRA_ACTION_INTENT);
+ PendingIntent pendingIntent =
+ intent.getParcelableExtra(EXTRA_ACTION_INTENT, PendingIntent.class);
+ Intent fillIn = intent.getParcelableExtra(EXTRA_ACTION_INTENT_FILLIN, Intent.class);
String actionType = intent.getStringExtra(EXTRA_ACTION_TYPE);
if (DEBUG_ACTIONS) {
Log.d(TAG, "Executing smart action [" + actionType + "]:" + pendingIntent.getIntent());
@@ -54,7 +57,7 @@ public class SmartActionsReceiver extends BroadcastReceiver {
ActivityOptions opts = ActivityOptions.makeBasic();
try {
- pendingIntent.send(context, 0, null, null, null, null, opts.toBundle());
+ pendingIntent.send(context, 0, fillIn, null, null, null, opts.toBundle());
} catch (PendingIntent.CanceledException e) {
Log.e(TAG, "Pending intent canceled", e);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/StatusEvent.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/StatusEvent.kt
index 4e1404d0637b..31d196b542d7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/events/StatusEvent.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/StatusEvent.kt
@@ -112,9 +112,7 @@ class PrivacyEvent(override val showAnimation: Boolean = true) : StatusEvent {
}
override fun shouldUpdateFromEvent(other: StatusEvent?): Boolean {
- return other is PrivacyEvent &&
- (other.privacyItems != privacyItems ||
- other.contentDescription != contentDescription)
+ return other is PrivacyEvent
}
override fun updateFromEvent(other: StatusEvent?) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
index c9c7fe9e0ab6..b9c912ff13cd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
@@ -21,6 +21,7 @@ import android.content.Context;
import android.content.pm.LauncherApps;
import android.content.pm.ShortcutManager;
import android.os.Handler;
+import android.os.UserManager;
import android.view.accessibility.AccessibilityManager;
import com.android.internal.logging.UiEventLogger;
@@ -160,6 +161,7 @@ public interface NotificationsModule {
HighPriorityProvider highPriorityProvider,
INotificationManager notificationManager,
NotificationEntryManager notificationEntryManager,
+ UserManager userManager,
PeopleSpaceWidgetManager peopleSpaceWidgetManager,
LauncherApps launcherApps,
ShortcutManager shortcutManager,
@@ -180,6 +182,7 @@ public interface NotificationsModule {
highPriorityProvider,
notificationManager,
notificationEntryManager,
+ userManager,
peopleSpaceWidgetManager,
launcherApps,
shortcutManager,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
index 134f24e7e646..d817244223c2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
@@ -48,6 +48,7 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.os.UserManager;
import android.service.notification.StatusBarNotification;
import android.text.TextUtils;
import android.transition.ChangeBounds;
@@ -118,6 +119,8 @@ public class NotificationConversationInfo extends LinearLayout implements
private NotificationGuts mGutsContainer;
private OnConversationSettingsClickListener mOnConversationSettingsClickListener;
+ private UserManager mUm;
+
@VisibleForTesting
boolean mSkipPost = false;
private int mActualHeight;
@@ -155,7 +158,9 @@ public class NotificationConversationInfo extends LinearLayout implements
// People Tile add request.
if (mSelectedAction == ACTION_FAVORITE && getPriority() != mSelectedAction) {
mShadeController.animateCollapsePanels();
- mPeopleSpaceWidgetManager.requestPinAppWidget(mShortcutInfo, new Bundle());
+ if (mUm.isSameProfileGroup(UserHandle.USER_SYSTEM, mSbn.getNormalizedUserId())) {
+ mPeopleSpaceWidgetManager.requestPinAppWidget(mShortcutInfo, new Bundle());
+ }
}
mGutsContainer.closeControls(v, true);
};
@@ -189,6 +194,7 @@ public class NotificationConversationInfo extends LinearLayout implements
@Action int selectedAction,
ShortcutManager shortcutManager,
PackageManager pm,
+ UserManager um,
PeopleSpaceWidgetManager peopleSpaceWidgetManager,
INotificationManager iNotificationManager,
OnUserInteractionCallback onUserInteractionCallback,
@@ -214,6 +220,7 @@ public class NotificationConversationInfo extends LinearLayout implements
mEntry = entry;
mSbn = entry.getSbn();
mPm = pm;
+ mUm = um;
mAppName = mPackageName;
mOnSettingsClickListener = onSettingsClick;
mNotificationChannel = notificationChannel;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
index 8a7155ac72d0..fb1462ae03fa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
@@ -31,6 +31,7 @@ import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.UserHandle;
+import android.os.UserManager;
import android.provider.Settings;
import android.service.notification.StatusBarNotification;
import android.util.ArraySet;
@@ -126,6 +127,9 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
private Runnable mOpenRunnable;
private final INotificationManager mNotificationManager;
private final PeopleSpaceWidgetManager mPeopleSpaceWidgetManager;
+
+ private final UserManager mUserManager;
+
private final LauncherApps mLauncherApps;
private final ShortcutManager mShortcutManager;
private final UserContextProvider mContextTracker;
@@ -145,6 +149,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
HighPriorityProvider highPriorityProvider,
INotificationManager notificationManager,
NotificationEntryManager notificationEntryManager,
+ UserManager userManager,
PeopleSpaceWidgetManager peopleSpaceWidgetManager,
LauncherApps launcherApps,
ShortcutManager shortcutManager,
@@ -163,6 +168,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
mAccessibilityManager = accessibilityManager;
mHighPriorityProvider = highPriorityProvider;
mNotificationManager = notificationManager;
+ mUserManager = userManager;
mPeopleSpaceWidgetManager = peopleSpaceWidgetManager;
mLauncherApps = launcherApps;
mShortcutManager = shortcutManager;
@@ -491,6 +497,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
notificationInfoView.getSelectedAction(),
mShortcutManager,
pmUser,
+ mUserManager,
mPeopleSpaceWidgetManager,
mNotificationManager,
mOnUserInteractionCallback,
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
index efc9921fe8b9..e717656c4c8a 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
@@ -55,6 +55,7 @@ import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.log.SessionTracker;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.UserSwitcherController;
import com.android.systemui.util.settings.GlobalSettings;
@@ -164,7 +165,8 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase {
mKeyguardStateController, mKeyguardSecurityViewFlipperController,
mConfigurationController, mFalsingCollector, mFalsingManager,
mUserSwitcherController, mFeatureFlags, mGlobalSettings,
- mSessionTracker).create(mSecurityCallback);
+ mSessionTracker, mock(DeviceProvisionedController.class))
+ .create(mSecurityCallback);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/CanUseIconPredicateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/CanUseIconPredicateTest.kt
new file mode 100644
index 000000000000..bfdb9231a9f8
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/CanUseIconPredicateTest.kt
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.controls.ui
+
+import android.content.ContentProvider
+import android.graphics.Bitmap
+import android.graphics.drawable.Icon
+import android.net.Uri
+import android.os.UserHandle
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class CanUseIconPredicateTest : SysuiTestCase() {
+
+ private companion object {
+ const val USER_ID_1 = 1
+ const val USER_ID_2 = 2
+ }
+
+ val underTest: CanUseIconPredicate = CanUseIconPredicate(USER_ID_1)
+
+ @Test
+ fun testReturnsFalseForDifferentUser() {
+ val user2Icon =
+ Icon.createWithContentUri(
+ ContentProvider.createContentUriForUser(
+ Uri.parse("content://test"),
+ UserHandle.of(USER_ID_2)
+ )
+ )
+
+ assertThat(underTest.invoke(user2Icon)).isFalse()
+ }
+
+ @Test
+ fun testReturnsTrueForCorrectUser() {
+ val user1Icon =
+ Icon.createWithContentUri(
+ ContentProvider.createContentUriForUser(
+ Uri.parse("content://test"),
+ UserHandle.of(USER_ID_1)
+ )
+ )
+
+ assertThat(underTest.invoke(user1Icon)).isTrue()
+ }
+
+ @Test
+ fun testReturnsTrueForUriWithoutUser() {
+ val uriIcon = Icon.createWithContentUri(Uri.parse("content://test"))
+
+ assertThat(underTest.invoke(uriIcon)).isTrue()
+ }
+
+ @Test
+ fun testReturnsTrueForNonUriIcon() {
+ val bitmapIcon = Icon.createWithBitmap(Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888))
+
+ assertThat(underTest.invoke(bitmapIcon)).isTrue()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlViewHolderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlViewHolderTest.kt
index d3c465dab438..42f28c8c6043 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlViewHolderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlViewHolderTest.kt
@@ -66,7 +66,8 @@ class ControlViewHolderTest : SysuiTestCase() {
FakeExecutor(clock),
mock(ControlActionCoordinator::class.java),
mock(ControlsMetricsLogger::class.java),
- uid = 100
+ uid = 100,
+ 0,
)
val cws = ControlWithState(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
index 1cce7cfb5b8a..52266f983fdd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
@@ -61,9 +61,11 @@ private const val KEY_2 = "KEY_2"
private const val KEY_MEDIA_SMARTSPACE = "MEDIA_SMARTSPACE_ID"
private const val PACKAGE_NAME = "com.example.app"
private const val SYSTEM_PACKAGE_NAME = "com.android.systemui"
-private const val APP_NAME = "SystemUI"
+private const val APP_NAME = "com.android.systemui.tests"
private const val SESSION_ARTIST = "artist"
private const val SESSION_TITLE = "title"
+private const val SESSION_BLANK_TITLE = " "
+private const val SESSION_EMPTY_TITLE = ""
private const val USER_ID = 0
private val DISMISS_INTENT = Intent().apply { action = "dismiss" }
@@ -339,6 +341,98 @@ class MediaDataManagerTest : SysuiTestCase() {
}
@Test
+ fun testOnNotificationAdded_emptyTitle_hasPlaceholder() {
+ // When the manager has a notification with an empty title
+ whenever(controller.metadata)
+ .thenReturn(
+ metadataBuilder
+ .putString(MediaMetadata.METADATA_KEY_TITLE, SESSION_EMPTY_TITLE)
+ .build()
+ )
+ mediaDataManager.onNotificationAdded(KEY, mediaNotification)
+
+ // Then a media control is created with a placeholder title string
+ assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
+ assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
+ verify(listener)
+ .onMediaDataLoaded(
+ eq(KEY),
+ eq(null),
+ capture(mediaDataCaptor),
+ eq(true),
+ eq(0),
+ eq(false)
+ )
+ val placeholderTitle = context.getString(R.string.controls_media_empty_title, APP_NAME)
+ assertThat(mediaDataCaptor.value.song).isEqualTo(placeholderTitle)
+ }
+
+ @Test
+ fun testOnNotificationAdded_blankTitle_hasPlaceholder() {
+ // GIVEN that the manager has a notification with a blank title
+ whenever(controller.metadata)
+ .thenReturn(
+ metadataBuilder
+ .putString(MediaMetadata.METADATA_KEY_TITLE, SESSION_BLANK_TITLE)
+ .build()
+ )
+ mediaDataManager.onNotificationAdded(KEY, mediaNotification)
+
+ // Then a media control is created with a placeholder title string
+ assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
+ assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
+ verify(listener)
+ .onMediaDataLoaded(
+ eq(KEY),
+ eq(null),
+ capture(mediaDataCaptor),
+ eq(true),
+ eq(0),
+ eq(false)
+ )
+ val placeholderTitle = context.getString(R.string.controls_media_empty_title, APP_NAME)
+ assertThat(mediaDataCaptor.value.song).isEqualTo(placeholderTitle)
+ }
+
+ @Test
+ fun testOnNotificationAdded_emptyMetadata_usesNotificationTitle() {
+ // When the app sets the metadata title fields to empty strings, but does include a
+ // non-blank notification title
+ whenever(controller.metadata)
+ .thenReturn(
+ metadataBuilder
+ .putString(MediaMetadata.METADATA_KEY_TITLE, SESSION_EMPTY_TITLE)
+ .putString(MediaMetadata.METADATA_KEY_DISPLAY_TITLE, SESSION_EMPTY_TITLE)
+ .build()
+ )
+ mediaNotification =
+ SbnBuilder().run {
+ setPkg(PACKAGE_NAME)
+ modifyNotification(context).also {
+ it.setSmallIcon(android.R.drawable.ic_media_pause)
+ it.setContentTitle(SESSION_TITLE)
+ it.setStyle(MediaStyle().apply { setMediaSession(session.sessionToken) })
+ }
+ build()
+ }
+ mediaDataManager.onNotificationAdded(KEY, mediaNotification)
+
+ // Then the media control is added using the notification's title
+ assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
+ assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
+ verify(listener)
+ .onMediaDataLoaded(
+ eq(KEY),
+ eq(null),
+ capture(mediaDataCaptor),
+ eq(true),
+ eq(0),
+ eq(false)
+ )
+ assertThat(mediaDataCaptor.value.song).isEqualTo(SESSION_TITLE)
+ }
+
+ @Test
fun testOnNotificationRemoved_withResumption() {
// GIVEN that the manager has a notification with a resume action
whenever(controller.metadata).thenReturn(metadataBuilder.build())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaResumeListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaResumeListenerTest.kt
index 3d3ac836d264..e7df1a219d3e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaResumeListenerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaResumeListenerTest.kt
@@ -87,6 +87,7 @@ class MediaResumeListenerTest : SysuiTestCase() {
@Captor lateinit var callbackCaptor: ArgumentCaptor<ResumeMediaBrowser.Callback>
@Captor lateinit var actionCaptor: ArgumentCaptor<Runnable>
@Captor lateinit var componentCaptor: ArgumentCaptor<String>
+ @Captor lateinit var userIdCaptor: ArgumentCaptor<Int>
private lateinit var executor: FakeExecutor
private lateinit var data: MediaData
@@ -107,7 +108,7 @@ class MediaResumeListenerTest : SysuiTestCase() {
Settings.Secure.putInt(context.contentResolver,
Settings.Secure.MEDIA_CONTROLS_RESUME, 1)
- whenever(resumeBrowserFactory.create(capture(callbackCaptor), any()))
+ whenever(resumeBrowserFactory.create(capture(callbackCaptor), any(), capture(userIdCaptor)))
.thenReturn(resumeBrowser)
// resume components are stored in sharedpreferences
@@ -118,6 +119,7 @@ class MediaResumeListenerTest : SysuiTestCase() {
whenever(sharedPrefsEditor.putString(any(), any())).thenReturn(sharedPrefsEditor)
whenever(mockContext.packageManager).thenReturn(context.packageManager)
whenever(mockContext.contentResolver).thenReturn(context.contentResolver)
+ whenever(mockContext.userId).thenReturn(context.userId)
executor = FakeExecutor(clock)
resumeListener = MediaResumeListener(mockContext, broadcastDispatcher, executor,
@@ -243,6 +245,7 @@ class MediaResumeListenerTest : SysuiTestCase() {
@Test
fun testOnUserUnlock_loadsTracks() {
// Set up mock service to successfully find valid media
+ setUpMbsWithValidResolveInfo()
val description = MediaDescription.Builder().setTitle(TITLE).build()
val component = ComponentName(PACKAGE_NAME, CLASS_NAME)
whenever(resumeBrowser.token).thenReturn(token)
@@ -316,6 +319,7 @@ class MediaResumeListenerTest : SysuiTestCase() {
@Test
fun testLoadComponents_recentlyPlayed_adds() {
// Set up browser to return successfully
+ setUpMbsWithValidResolveInfo()
val description = MediaDescription.Builder().setTitle(TITLE).build()
val component = ComponentName(PACKAGE_NAME, CLASS_NAME)
whenever(resumeBrowser.token).thenReturn(token)
@@ -464,7 +468,7 @@ class MediaResumeListenerTest : SysuiTestCase() {
// Set up our factory to return a new browser so we can verify we disconnected the old one
val newResumeBrowser = mock(ResumeMediaBrowser::class.java)
- whenever(resumeBrowserFactory.create(capture(callbackCaptor), any()))
+ whenever(resumeBrowserFactory.create(capture(callbackCaptor), any(), anyInt()))
.thenReturn(newResumeBrowser)
// When the resume action is run
@@ -474,6 +478,68 @@ class MediaResumeListenerTest : SysuiTestCase() {
verify(resumeBrowser).disconnect()
}
+ @Test
+ fun testUserUnlocked_userChangeWhileQuerying() {
+ val firstUserId = context.userId
+ val secondUserId = firstUserId + 1
+ val description = MediaDescription.Builder().setTitle(TITLE).build()
+ val component = ComponentName(PACKAGE_NAME, CLASS_NAME)
+
+ setUpMbsWithValidResolveInfo()
+ whenever(resumeBrowser.token).thenReturn(token)
+ whenever(resumeBrowser.appIntent).thenReturn(pendingIntent)
+
+ val unlockIntent =
+ Intent(Intent.ACTION_USER_UNLOCKED).apply {
+ putExtra(Intent.EXTRA_USER_HANDLE, firstUserId)
+ }
+
+ // When the first user unlocks and we query their recent media
+ resumeListener.userChangeReceiver.onReceive(context, unlockIntent)
+ whenever(resumeBrowser.userId).thenReturn(userIdCaptor.value)
+ verify(resumeBrowser, times(3)).findRecentMedia()
+
+ // And the user changes before the MBS response is received
+ val changeIntent =
+ Intent(Intent.ACTION_USER_SWITCHED).apply {
+ putExtra(Intent.EXTRA_USER_HANDLE, secondUserId)
+ }
+ resumeListener.userChangeReceiver.onReceive(context, changeIntent)
+ callbackCaptor.value.addTrack(description, component, resumeBrowser)
+
+ // Then the loaded media is correctly associated with the first user
+ verify(mediaDataManager)
+ .addResumptionControls(
+ eq(firstUserId),
+ eq(description),
+ any(),
+ eq(token),
+ eq(PACKAGE_NAME),
+ eq(pendingIntent),
+ eq(PACKAGE_NAME)
+ )
+ }
+
+ @Test
+ fun testUserUnlocked_noComponent_doesNotQuery() {
+ // Set up a valid MBS, but user does not have the service available
+ setUpMbsWithValidResolveInfo()
+ val pm = mock(PackageManager::class.java)
+ whenever(mockContext.packageManager).thenReturn(pm)
+ whenever(pm.resolveServiceAsUser(any(), anyInt(), anyInt())).thenReturn(null)
+
+ val unlockIntent =
+ Intent(Intent.ACTION_USER_UNLOCKED).apply {
+ putExtra(Intent.EXTRA_USER_HANDLE, context.userId)
+ }
+
+ // When the user is unlocked, but does not have the component installed
+ resumeListener.userChangeReceiver.onReceive(context, unlockIntent)
+
+ // Then we never attempt to connect to it
+ verify(resumeBrowser, never()).findRecentMedia()
+ }
+
/** Sets up mocks to successfully find a MBS that returns valid media. */
private fun setUpMbsWithValidResolveInfo() {
val pm = mock(PackageManager::class.java)
@@ -484,6 +550,8 @@ class MediaResumeListenerTest : SysuiTestCase() {
resolveInfo.serviceInfo = serviceInfo
resolveInfo.serviceInfo.name = CLASS_NAME
val resumeInfo = listOf(resolveInfo)
- whenever(pm.queryIntentServices(any(), anyInt())).thenReturn(resumeInfo)
+ whenever(pm.queryIntentServicesAsUser(any(), anyInt(), anyInt())).thenReturn(resumeInfo)
+ whenever(pm.resolveServiceAsUser(any(), anyInt(), anyInt())).thenReturn(resolveInfo)
+ whenever(pm.getApplicationLabel(any())).thenReturn(PACKAGE_NAME)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/ResumeMediaBrowserTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/ResumeMediaBrowserTest.kt
index dafaa6b93696..e3134d482955 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/ResumeMediaBrowserTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/ResumeMediaBrowserTest.kt
@@ -92,7 +92,8 @@ public class ResumeMediaBrowserTest : SysuiTestCase() {
component,
browserFactory,
logger,
- mediaController
+ mediaController,
+ context.userId
)
}
@@ -396,8 +397,9 @@ public class ResumeMediaBrowserTest : SysuiTestCase() {
componentName: ComponentName,
browserFactory: MediaBrowserFactory,
logger: ResumeMediaBrowserLogger,
- private val fakeController: MediaController
- ) : ResumeMediaBrowser(context, callback, componentName, browserFactory, logger) {
+ private val fakeController: MediaController,
+ userId: Int
+ ) : ResumeMediaBrowser(context, callback, componentName, browserFactory, logger, userId) {
override fun createMediaController(token: MediaSession.Token): MediaController {
return fakeController
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/SaveImageInBackgroundTaskTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/SaveImageInBackgroundTaskTest.kt
new file mode 100644
index 000000000000..03f8c9394218
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/SaveImageInBackgroundTaskTest.kt
@@ -0,0 +1,282 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.screenshot
+
+import android.app.Notification
+import android.app.PendingIntent
+import android.content.ComponentName
+import android.content.Intent
+import android.graphics.Bitmap
+import android.graphics.drawable.Icon
+import android.net.Uri
+import android.os.UserHandle
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.screenshot.ScreenshotController.SaveImageInBackgroundData
+import com.android.systemui.screenshot.ScreenshotNotificationSmartActionsProvider.ScreenshotSmartActionType
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.mockito.mock
+import java.util.concurrent.CompletableFuture
+import java.util.function.Supplier
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertNull
+import org.junit.Before
+import org.junit.runner.RunWith
+import org.junit.Test
+import org.mockito.Mockito
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class SaveImageInBackgroundTaskTest : SysuiTestCase() {
+ private val imageExporter = mock<ImageExporter>()
+ private val smartActions = mock<ScreenshotSmartActions>()
+ private val saveImageData = SaveImageInBackgroundData()
+ private val sharedTransitionSupplier =
+ mock<Supplier<ScreenshotController.SavedImageData.ActionTransition>>()
+ private val testScreenshotId: String = "testScreenshotId"
+ private val testBitmap = mock<Bitmap>()
+ private val testUser = UserHandle.getUserHandleForUid(0)
+ private val testIcon = mock<Icon>()
+ private val testImageTime = 1234.toLong()
+
+ private val smartActionsUriFuture = mock<CompletableFuture<List<Notification.Action>>>()
+ private val smartActionsFuture = mock<CompletableFuture<List<Notification.Action>>>()
+
+ private val testUri: Uri = Uri.parse("testUri")
+ private val intent =
+ Intent(Intent.ACTION_SEND)
+ .setComponent(
+ ComponentName.unflattenFromString(
+ "com.google.android.test/com.google.android.test.TestActivity"
+ )
+ )
+ private val immutablePendingIntent =
+ PendingIntent.getBroadcast(
+ mContext,
+ 0,
+ intent,
+ PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_IMMUTABLE
+ )
+ private val mutablePendingIntent =
+ PendingIntent.getBroadcast(
+ mContext,
+ 0,
+ intent,
+ PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_MUTABLE
+ )
+
+ private val saveImageTask =
+ SaveImageInBackgroundTask(
+ mContext,
+ imageExporter,
+ smartActions,
+ saveImageData,
+ sharedTransitionSupplier,
+ )
+
+ @Before
+ fun setup() {
+ Mockito.`when`(
+ smartActions.getSmartActionsFuture(
+ eq(testScreenshotId),
+ any(Uri::class.java),
+ eq(testBitmap),
+ any(ScreenshotNotificationSmartActionsProvider::class.java),
+ any(ScreenshotSmartActionType::class.java),
+ any(Boolean::class.java),
+ eq(testUser)
+ )
+ )
+ .thenReturn(smartActionsUriFuture)
+ Mockito.`when`(
+ smartActions.getSmartActionsFuture(
+ eq(testScreenshotId),
+ eq(null),
+ eq(testBitmap),
+ any(ScreenshotNotificationSmartActionsProvider::class.java),
+ any(ScreenshotSmartActionType::class.java),
+ any(Boolean::class.java),
+ eq(testUser)
+ )
+ )
+ .thenReturn(smartActionsFuture)
+ }
+
+ @Test
+ fun testQueryQuickShare_noAction() {
+ Mockito.`when`(
+ smartActions.getSmartActions(
+ eq(testScreenshotId),
+ eq(smartActionsFuture),
+ any(Int::class.java),
+ any(ScreenshotNotificationSmartActionsProvider::class.java),
+ eq(ScreenshotSmartActionType.QUICK_SHARE_ACTION)
+ )
+ )
+ .thenReturn(ArrayList<Notification.Action>())
+
+ val quickShareAction =
+ saveImageTask.queryQuickShareAction(testScreenshotId, testBitmap, testUser, testUri)
+
+ assertNull(quickShareAction)
+ }
+
+ @Test
+ fun testQueryQuickShare_withActions() {
+ val actions = ArrayList<Notification.Action>()
+ actions.add(constructAction("Action One", mutablePendingIntent))
+ actions.add(constructAction("Action Two", mutablePendingIntent))
+ Mockito.`when`(
+ smartActions.getSmartActions(
+ eq(testScreenshotId),
+ eq(smartActionsUriFuture),
+ any(Int::class.java),
+ any(ScreenshotNotificationSmartActionsProvider::class.java),
+ eq(ScreenshotSmartActionType.QUICK_SHARE_ACTION)
+ )
+ )
+ .thenReturn(actions)
+
+ val quickShareAction =
+ saveImageTask.queryQuickShareAction(testScreenshotId, testBitmap, testUser, testUri)!!
+
+ assertEquals("Action One", quickShareAction.title)
+ assertEquals(mutablePendingIntent, quickShareAction.actionIntent)
+ }
+
+ @Test
+ fun testCreateQuickShareAction_originalWasNull_returnsNull() {
+ val quickShareAction =
+ saveImageTask.createQuickShareAction(
+ null,
+ testScreenshotId,
+ testUri,
+ testImageTime,
+ testBitmap,
+ testUser
+ )
+
+ assertNull(quickShareAction)
+ }
+
+ @Test
+ fun testCreateQuickShareAction_immutableIntentDifferentAction_returnsNull() {
+ val actions = ArrayList<Notification.Action>()
+ actions.add(constructAction("New Test Action", immutablePendingIntent))
+ Mockito.`when`(
+ smartActions.getSmartActions(
+ eq(testScreenshotId),
+ eq(smartActionsUriFuture),
+ any(Int::class.java),
+ any(ScreenshotNotificationSmartActionsProvider::class.java),
+ eq(ScreenshotSmartActionType.QUICK_SHARE_ACTION)
+ )
+ )
+ .thenReturn(actions)
+ val origAction = constructAction("Old Test Action", immutablePendingIntent)
+
+ val quickShareAction =
+ saveImageTask.createQuickShareAction(
+ origAction,
+ testScreenshotId,
+ testUri,
+ testImageTime,
+ testBitmap,
+ testUser,
+ )
+
+ assertNull(quickShareAction)
+ }
+
+ @Test
+ fun testCreateQuickShareAction_mutableIntent_returnsSafeIntent() {
+ val actions = ArrayList<Notification.Action>()
+ val action = constructAction("Action One", mutablePendingIntent)
+ actions.add(action)
+ Mockito.`when`(
+ smartActions.getSmartActions(
+ eq(testScreenshotId),
+ eq(smartActionsUriFuture),
+ any(Int::class.java),
+ any(ScreenshotNotificationSmartActionsProvider::class.java),
+ eq(ScreenshotSmartActionType.QUICK_SHARE_ACTION)
+ )
+ )
+ .thenReturn(actions)
+
+ val quickShareAction =
+ saveImageTask.createQuickShareAction(
+ constructAction("Test Action", mutablePendingIntent),
+ testScreenshotId,
+ testUri,
+ testImageTime,
+ testBitmap,
+ testUser
+ )
+ val quickSharePendingIntent =
+ quickShareAction.actionIntent.intent.extras!!.getParcelable(
+ ScreenshotController.EXTRA_ACTION_INTENT,
+ PendingIntent::class.java
+ )
+
+ assertEquals("Test Action", quickShareAction.title)
+ assertEquals(mutablePendingIntent, quickSharePendingIntent)
+ }
+
+ @Test
+ fun testCreateQuickShareAction_immutableIntent_returnsSafeIntent() {
+ val actions = ArrayList<Notification.Action>()
+ val action = constructAction("Test Action", immutablePendingIntent)
+ actions.add(action)
+ Mockito.`when`(
+ smartActions.getSmartActions(
+ eq(testScreenshotId),
+ eq(smartActionsUriFuture),
+ any(Int::class.java),
+ any(ScreenshotNotificationSmartActionsProvider::class.java),
+ eq(ScreenshotSmartActionType.QUICK_SHARE_ACTION)
+ )
+ )
+ .thenReturn(actions)
+
+ val quickShareAction =
+ saveImageTask.createQuickShareAction(
+ constructAction("Test Action", immutablePendingIntent),
+ testScreenshotId,
+ testUri,
+ testImageTime,
+ testBitmap,
+ testUser,
+ )!!
+
+ assertEquals("Test Action", quickShareAction.title)
+ assertEquals(
+ immutablePendingIntent,
+ quickShareAction.actionIntent.intent.extras!!.getParcelable(
+ ScreenshotController.EXTRA_ACTION_INTENT,
+ PendingIntent::class.java
+ )
+ )
+ }
+
+ private fun constructAction(title: String, intent: PendingIntent): Notification.Action {
+ return Notification.Action.Builder(testIcon, title, intent).build()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
index dc6d744637b5..f76a40f99310 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
@@ -62,6 +62,7 @@ import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.os.Handler;
import android.os.UserHandle;
+import android.os.UserManager;
import android.service.notification.StatusBarNotification;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
@@ -132,6 +133,8 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
@Mock
private PackageManager mMockPackageManager;
@Mock
+ private UserManager mUserManager;
+ @Mock
private OnUserInteractionCallback mOnUserInteractionCallback;
@Mock
private BubblesManager mBubblesManager;
@@ -239,6 +242,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
-1,
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -264,6 +268,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
-1,
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -317,6 +322,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
-1,
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -343,6 +349,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
-1,
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -368,6 +375,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
-1,
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -404,6 +412,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
-1,
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -430,6 +439,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
-1,
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -460,6 +470,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
-1,
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -485,6 +496,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
-1,
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -514,6 +526,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
-1,
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -543,6 +556,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
-1,
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -575,6 +589,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
-1,
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -613,6 +628,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
-1,
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -642,6 +658,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
-1,
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -678,6 +695,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
-1,
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -707,6 +725,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
-1,
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -752,6 +771,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
-1,
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -796,6 +816,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
-1,
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -841,6 +862,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
-1,
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -879,6 +901,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
-1,
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -916,6 +939,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
-1,
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -957,6 +981,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
-1, // no action selected by default
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -988,6 +1013,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
NotificationConversationInfo.ACTION_FAVORITE, // "Favorite" selected by default
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -1018,6 +1044,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
-1,
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -1055,6 +1082,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
-1,
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -1092,6 +1120,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
-1,
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -1128,6 +1157,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
-1,
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -1163,6 +1193,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
-1,
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -1189,6 +1220,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
-1,
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -1210,12 +1242,14 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
@Test
public void testSelectPriorityRequestsPinPeopleTile() {
+ when(mUserManager.isSameProfileGroup(anyInt(), anyInt())).thenReturn(true);
//WHEN channel is default importance
mNotificationChannel.setImportantConversation(false);
mNotificationInfo.bindNotification(
-1,
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -1242,11 +1276,47 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
}
@Test
+ public void testSelectPriorityRequestsPinPeopleTile_noMultiuser() {
+ when(mUserManager.isSameProfileGroup(anyInt(), anyInt())).thenReturn(false);
+ //WHEN channel is default importance
+ mNotificationChannel.setImportantConversation(false);
+ mNotificationInfo.bindNotification(
+ -1,
+ mShortcutManager,
+ mMockPackageManager,
+ mUserManager,
+ mPeopleSpaceWidgetManager,
+ mMockINotificationManager,
+ mOnUserInteractionCallback,
+ TEST_PACKAGE_NAME,
+ mNotificationChannel,
+ mEntry,
+ mBubbleMetadata,
+ null,
+ mIconFactory,
+ mContext,
+ true,
+ mTestHandler,
+ mTestHandler, null, Optional.of(mBubblesManager),
+ mShadeController);
+
+ // WHEN user clicks "priority"
+ mNotificationInfo.setSelectedAction(NotificationConversationInfo.ACTION_FAVORITE);
+
+ // and then done
+ mNotificationInfo.findViewById(R.id.done).performClick();
+
+ // No widget prompt; on a secondary user
+ verify(mPeopleSpaceWidgetManager, never()).requestPinAppWidget(any(), any());
+ }
+
+ @Test
public void testSelectDefaultDoesNotRequestPinPeopleTile() {
mNotificationInfo.bindNotification(
-1,
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -1282,6 +1352,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
-1,
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
index e9d8f5830131..6da97404e742 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
@@ -54,6 +54,7 @@ import android.content.pm.ShortcutManager;
import android.graphics.Color;
import android.os.Binder;
import android.os.Handler;
+import android.os.UserManager;
import android.provider.Settings;
import android.service.notification.StatusBarNotification;
import android.testing.AndroidTestingRunner;
@@ -139,6 +140,8 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
@Mock private PeopleSpaceWidgetManager mPeopleSpaceWidgetManager;
@Mock private AssistantFeedbackController mAssistantFeedbackController;
+ @Mock private UserManager mUserManager;
+
@Before
public void setUp() {
mTestableLooper = TestableLooper.get(this);
@@ -157,6 +160,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
mGutsManager = new NotificationGutsManager(mContext,
() -> Optional.of(mCentralSurfaces), mHandler, mHandler, mAccessibilityManager,
mHighPriorityProvider, mINotificationManager, mNotificationEntryManager,
+ mUserManager,
mPeopleSpaceWidgetManager, mLauncherApps, mShortcutManager,
mChannelEditorDialogController, mContextTracker, mAssistantFeedbackController,
Optional.of(mBubblesManager), new UiEventLoggerFake(), mOnUserInteractionCallback,
diff --git a/services/autofill/java/com/android/server/autofill/Helper.java b/services/autofill/java/com/android/server/autofill/Helper.java
index bc5d6457c945..48113a81cca5 100644
--- a/services/autofill/java/com/android/server/autofill/Helper.java
+++ b/services/autofill/java/com/android/server/autofill/Helper.java
@@ -18,6 +18,8 @@ package com.android.server.autofill;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.app.ActivityManager;
import android.app.assist.AssistStructure;
import android.app.assist.AssistStructure.ViewNode;
import android.app.assist.AssistStructure.WindowNode;
@@ -34,6 +36,7 @@ import android.view.View;
import android.view.WindowManager;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillValue;
+import android.widget.RemoteViews;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.util.ArrayUtils;
@@ -42,6 +45,8 @@ import java.io.PrintWriter;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.concurrent.atomic.AtomicBoolean;
+
public final class Helper {
@@ -75,6 +80,44 @@ public final class Helper {
throw new UnsupportedOperationException("contains static members only");
}
+ private static boolean checkRemoteViewUriPermissions(
+ @UserIdInt int userId, @NonNull RemoteViews rView) {
+ final AtomicBoolean permissionsOk = new AtomicBoolean(true);
+
+ rView.visitUris(uri -> {
+ int uriOwnerId = android.content.ContentProvider.getUserIdFromUri(uri);
+ boolean allowed = uriOwnerId == userId;
+ permissionsOk.set(allowed && permissionsOk.get());
+ });
+
+ return permissionsOk.get();
+ }
+
+ /**
+ * Checks the URI permissions of the remote view,
+ * to see if the current userId is able to access it.
+ *
+ * Returns the RemoteView that is passed if user is able, null otherwise.
+ *
+ * TODO: instead of returning a null remoteview when
+ * the current userId cannot access an URI,
+ * return a new RemoteView with the URI removed.
+ */
+ public static @Nullable RemoteViews sanitizeRemoteView(RemoteViews rView) {
+ if (rView == null) return null;
+
+ int userId = ActivityManager.getCurrentUser();
+
+ boolean ok = checkRemoteViewUriPermissions(userId, rView);
+ if (!ok) {
+ Slog.w(TAG,
+ "sanitizeRemoteView() user: " + userId
+ + " tried accessing resource that does not belong to them");
+ }
+ return (ok ? rView : null);
+ }
+
+
@Nullable
static AutofillId[] toArray(@Nullable ArraySet<AutofillId> set) {
if (set == null) return null;
diff --git a/services/autofill/java/com/android/server/autofill/ui/DialogFillUi.java b/services/autofill/java/com/android/server/autofill/ui/DialogFillUi.java
index c2c630e01bee..59184e9ed288 100644
--- a/services/autofill/java/com/android/server/autofill/ui/DialogFillUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/DialogFillUi.java
@@ -52,6 +52,7 @@ import android.widget.TextView;
import com.android.internal.R;
import com.android.server.autofill.AutofillManagerService;
+import com.android.server.autofill.Helper;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -197,7 +198,8 @@ final class DialogFillUi {
}
private void setHeader(View decor, FillResponse response) {
- final RemoteViews presentation = response.getDialogHeader();
+ final RemoteViews presentation =
+ Helper.sanitizeRemoteView(response.getDialogHeader());
if (presentation == null) {
return;
}
@@ -232,9 +234,10 @@ final class DialogFillUi {
}
private void initialAuthenticationLayout(View decor, FillResponse response) {
- RemoteViews presentation = response.getDialogPresentation();
+ RemoteViews presentation = Helper.sanitizeRemoteView(
+ response.getDialogPresentation());
if (presentation == null) {
- presentation = response.getPresentation();
+ presentation = Helper.sanitizeRemoteView(response.getPresentation());
}
if (presentation == null) {
throw new RuntimeException("No presentation for fill dialog authentication");
@@ -278,7 +281,8 @@ final class DialogFillUi {
final Dataset dataset = response.getDatasets().get(i);
final int index = dataset.getFieldIds().indexOf(focusedViewId);
if (index >= 0) {
- RemoteViews presentation = dataset.getFieldDialogPresentation(index);
+ RemoteViews presentation = Helper.sanitizeRemoteView(
+ dataset.getFieldDialogPresentation(index));
if (presentation == null) {
if (sDebug) {
Slog.w(TAG, "not displaying UI on field " + focusedViewId + " because "
diff --git a/services/autofill/java/com/android/server/autofill/ui/FillUi.java b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
index 8fbdd81cc4cc..76fa258734cc 100644
--- a/services/autofill/java/com/android/server/autofill/ui/FillUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
@@ -144,8 +144,9 @@ final class FillUi {
final LayoutInflater inflater = LayoutInflater.from(mContext);
- final RemoteViews headerPresentation = response.getHeader();
- final RemoteViews footerPresentation = response.getFooter();
+ final RemoteViews headerPresentation = Helper.sanitizeRemoteView(response.getHeader());
+ final RemoteViews footerPresentation = Helper.sanitizeRemoteView(response.getFooter());
+
final ViewGroup decor;
if (mFullScreen) {
decor = (ViewGroup) inflater.inflate(R.layout.autofill_dataset_picker_fullscreen, null);
@@ -223,6 +224,9 @@ final class FillUi {
ViewGroup container = decor.findViewById(R.id.autofill_dataset_picker);
final View content;
try {
+ if (Helper.sanitizeRemoteView(response.getPresentation()) == null) {
+ throw new RuntimeException("Permission error accessing RemoteView");
+ }
content = response.getPresentation().applyWithTheme(
mContext, decor, interceptionHandler, mThemeId);
container.addView(content);
@@ -302,7 +306,8 @@ final class FillUi {
final Dataset dataset = response.getDatasets().get(i);
final int index = dataset.getFieldIds().indexOf(focusedViewId);
if (index >= 0) {
- final RemoteViews presentation = dataset.getFieldPresentation(index);
+ final RemoteViews presentation = Helper.sanitizeRemoteView(
+ dataset.getFieldPresentation(index));
if (presentation == null) {
Slog.w(TAG, "not displaying UI on field " + focusedViewId + " because "
+ "service didn't provide a presentation for it on " + dataset);
diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
index 677871f6c85f..533a7b69a650 100644
--- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
@@ -368,8 +368,7 @@ final class SaveUi {
return false;
}
writeLog(MetricsEvent.AUTOFILL_SAVE_CUSTOM_DESCRIPTION);
-
- final RemoteViews template = customDescription.getPresentation();
+ final RemoteViews template = Helper.sanitizeRemoteView(customDescription.getPresentation());
if (template == null) {
Slog.w(TAG, "No remote view on custom description");
return false;
diff --git a/services/core/java/com/android/server/PendingIntentUtils.java b/services/core/java/com/android/server/PendingIntentUtils.java
index 1600101b20f4..a72a4d254a2a 100644
--- a/services/core/java/com/android/server/PendingIntentUtils.java
+++ b/services/core/java/com/android/server/PendingIntentUtils.java
@@ -34,6 +34,7 @@ public class PendingIntentUtils {
public static Bundle createDontSendToRestrictedAppsBundle(@Nullable Bundle bundle) {
final BroadcastOptions options = BroadcastOptions.makeBasic();
options.setDontSendToRestrictedApps(true);
+ options.setPendingIntentBackgroundActivityLaunchAllowed(false);
if (bundle == null) {
return options.toBundle();
}
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 639f35e1ae13..7a19d034c2c8 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -4923,7 +4923,10 @@ public class AccountManagerService
p.setDataPosition(0);
Bundle simulateBundle = p.readBundle();
p.recycle();
- Intent intent = bundle.getParcelable(AccountManager.KEY_INTENT, Intent.class);
+ Intent intent = bundle.getParcelable(AccountManager.KEY_INTENT);
+ if (intent != null && intent.getClass() != Intent.class) {
+ return false;
+ }
Intent simulateIntent = simulateBundle.getParcelable(AccountManager.KEY_INTENT,
Intent.class);
if (intent == null) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 570c8d4075cd..5f5912bf2143 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2988,6 +2988,22 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
+ /**
+ * Enforces that the uid of the caller matches the uid of the package.
+ *
+ * @param packageName the name of the package to match uid against.
+ * @param callingUid the uid of the caller.
+ * @throws SecurityException if the calling uid doesn't match uid of the package.
+ */
+ private void enforceCallingPackage(String packageName, int callingUid) {
+ final int userId = UserHandle.getUserId(callingUid);
+ final int packageUid = getPackageManagerInternal().getPackageUid(packageName,
+ /*flags=*/ 0, userId);
+ if (packageUid != callingUid) {
+ throw new SecurityException(packageName + " does not belong to uid " + callingUid);
+ }
+ }
+
@Override
public void setPackageScreenCompatMode(String packageName, int mode) {
mActivityTaskManager.setPackageScreenCompatMode(packageName, mode);
@@ -9216,6 +9232,13 @@ public class ActivityManagerService extends IActivityManager.Stub
public void onShellCommand(FileDescriptor in, FileDescriptor out,
FileDescriptor err, String[] args, ShellCallback callback,
ResultReceiver resultReceiver) {
+ final int callingUid = Binder.getCallingUid();
+ if (callingUid != ROOT_UID && callingUid != Process.SHELL_UID) {
+ if (resultReceiver != null) {
+ resultReceiver.send(-1, null);
+ }
+ throw new SecurityException("Shell commands are only callable by root or shell");
+ }
(new ActivityManagerShellCommand(this, false)).exec(
this, in, out, err, args, callback, resultReceiver);
}
@@ -12918,13 +12941,16 @@ public class ActivityManagerService extends IActivityManager.Stub
// A backup agent has just come up
@Override
public void backupAgentCreated(String agentPackageName, IBinder agent, int userId) {
+ final int callingUid = Binder.getCallingUid();
+ enforceCallingPackage(agentPackageName, callingUid);
+
// Resolve the target user id and enforce permissions.
- userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
+ userId = mUserController.handleIncomingUser(Binder.getCallingPid(), callingUid,
userId, /* allowAll */ false, ALLOW_FULL_ONLY, "backupAgentCreated", null);
if (DEBUG_BACKUP) {
Slog.v(TAG_BACKUP, "backupAgentCreated: " + agentPackageName + " = " + agent
+ " callingUserId = " + UserHandle.getCallingUserId() + " userId = " + userId
- + " callingUid = " + Binder.getCallingUid() + " uid = " + Process.myUid());
+ + " callingUid = " + callingUid + " uid = " + Process.myUid());
}
synchronized(this) {
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 78cffa6f4f79..62ae4aae2b4d 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -2992,9 +2992,19 @@ public class LockSettingsService extends ILockSettings.Stub {
}
activateEscrowTokens(authToken, userId);
- if (isProfileWithSeparatedLock(userId)) {
- setDeviceUnlockedForUser(userId);
+ if (isCredentialSharableWithParent(userId)) {
+ if (getSeparateProfileChallengeEnabledInternal(userId)) {
+ setDeviceUnlockedForUser(userId);
+ } else {
+ // Here only clear StrongAuthFlags for a profile that has a unified challenge.
+ // StrongAuth for a profile with a separate challenge is handled differently and
+ // is cleared after the user successfully confirms the separate challenge to enter
+ // the profile. StrongAuth for the full user (e.g. userId 0) is also handled
+ // separately by Keyguard.
+ mStrongAuth.reportUnlock(userId);
+ }
}
+
mStrongAuth.reportSuccessfulStrongAuthUnlock(userId);
onAuthTokenKnownForUser(userId, authToken);
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index cc4895ffaf24..b459cfe6b44e 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -22,6 +22,8 @@ import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.app.PendingIntent;
import android.content.ComponentName;
+import android.content.ContentProvider;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
@@ -63,6 +65,9 @@ import android.util.EventLog;
import android.util.Log;
import android.view.KeyEvent;
+import com.android.server.LocalServices;
+import com.android.server.uri.UriGrantsManagerInternal;
+
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
@@ -78,6 +83,10 @@ import java.util.concurrent.CopyOnWriteArrayList;
// TODO(jaewan): Do not call service method directly -- introduce listener instead.
public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionRecordImpl {
private static final String TAG = "MediaSessionRecord";
+ private static final String[] ART_URIS = new String[] {
+ MediaMetadata.METADATA_KEY_ALBUM_ART_URI,
+ MediaMetadata.METADATA_KEY_ART_URI,
+ MediaMetadata.METADATA_KEY_DISPLAY_ICON_URI};
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
/**
@@ -131,6 +140,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
private final SessionStub mSession;
private final SessionCb mSessionCb;
private final MediaSessionService mService;
+ private final UriGrantsManagerInternal mUgmInternal;
private final Context mContext;
private final boolean mVolumeAdjustmentForRemoteGroupSessions;
@@ -192,6 +202,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
mAudioAttrs = DEFAULT_ATTRIBUTES;
mPolicies = policies;
+ mUgmInternal = LocalServices.getService(UriGrantsManagerInternal.class);
mVolumeAdjustmentForRemoteGroupSessions = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_volumeAdjustmentForRemoteGroupSessions);
@@ -1018,21 +1029,45 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
public void setMetadata(MediaMetadata metadata, long duration, String metadataDescription)
throws RemoteException {
synchronized (mLock) {
- MediaMetadata temp = metadata == null ? null : new MediaMetadata.Builder(metadata)
- .build();
- // This is to guarantee that the underlying bundle is unparceled
- // before we set it to prevent concurrent reads from throwing an
- // exception
- if (temp != null) {
- temp.size();
- }
- mMetadata = temp;
mDuration = duration;
mMetadataDescription = metadataDescription;
+ mMetadata = sanitizeMediaMetadata(metadata);
}
mHandler.post(MessageHandler.MSG_UPDATE_METADATA);
}
+ private MediaMetadata sanitizeMediaMetadata(MediaMetadata metadata) {
+ if (metadata == null) {
+ return null;
+ }
+ MediaMetadata.Builder metadataBuilder = new MediaMetadata.Builder(metadata);
+ for (String key: ART_URIS) {
+ String uriString = metadata.getString(key);
+ if (TextUtils.isEmpty(uriString)) {
+ continue;
+ }
+ Uri uri = Uri.parse(uriString);
+ if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
+ continue;
+ }
+ try {
+ mUgmInternal.checkGrantUriPermission(getUid(),
+ getPackageName(),
+ ContentProvider.getUriWithoutUserId(uri),
+ Intent.FLAG_GRANT_READ_URI_PERMISSION,
+ ContentProvider.getUserIdFromUri(uri, getUserId()));
+ } catch (SecurityException e) {
+ metadataBuilder.putString(key, null);
+ }
+ }
+ MediaMetadata sanitizedMetadata = metadataBuilder.build();
+ // sanitizedMetadata.size() guarantees that the underlying bundle is unparceled
+ // before we set it to prevent concurrent reads from throwing an
+ // exception
+ sanitizedMetadata.size();
+ return sanitizedMetadata;
+ }
+
@Override
public void setPlaybackState(PlaybackState state) throws RemoteException {
int oldState = mPlaybackState == null
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index c39c722170c1..4ddc72ed610b 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -4341,7 +4341,7 @@ public class NotificationManagerService extends SystemService {
// Remove background token before returning notification to untrusted app, this
// ensures the app isn't able to perform background operations that are
// associated with notification interactions.
- notification.setAllowlistToken(null);
+ notification.clearAllowlistToken();
return new StatusBarNotification(
sbn.getPackageName(),
sbn.getOpPkg(),
@@ -5449,6 +5449,11 @@ public class NotificationManagerService extends SystemService {
boolean granted, boolean userSet) {
Objects.requireNonNull(listener);
checkNotificationListenerAccess();
+ if (granted && listener.flattenToString().length()
+ > NotificationManager.MAX_SERVICE_COMPONENT_NAME_LENGTH) {
+ throw new IllegalArgumentException(
+ "Component name too long: " + listener.flattenToString());
+ }
if (!userSet && isNotificationListenerAccessUserSet(listener)) {
// Don't override user's choice
return;
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index 8507ad028a19..1b7687e6fc16 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -376,6 +376,7 @@ class ShortcutPackage extends ShortcutPackageItem {
// Extract Icon and update the icon res ID and the bitmap path.
s.saveIconAndFixUpShortcutLocked(this, newShortcut);
s.fixUpShortcutResourceNamesAndValues(newShortcut);
+ ensureShortcutCountBeforePush();
saveShortcut(newShortcut);
}
@@ -430,7 +431,6 @@ class ShortcutPackage extends ShortcutPackageItem {
@NonNull List<ShortcutInfo> changedShortcuts) {
Preconditions.checkArgument(newShortcut.isEnabled(),
"pushDynamicShortcuts() cannot publish disabled shortcuts");
- ensureShortcutCountBeforePush();
newShortcut.addFlags(ShortcutInfo.FLAG_DYNAMIC);
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 2f3056e89614..63a6328ea6d7 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -34,6 +34,7 @@ import android.app.usage.UsageStatsManagerInternal;
import android.appwidget.AppWidgetProviderInfo;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
+import android.content.ContentProvider;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -1728,6 +1729,10 @@ public class ShortcutService extends IShortcutService.Stub {
android.util.EventLog.writeEvent(0x534e4554, "109824443", -1, "");
throw new SecurityException("Shortcut package name mismatch");
}
+ final int callingUid = injectBinderCallingUid();
+ if (UserHandle.getUserId(callingUid) != si.getUserId()) {
+ throw new SecurityException("User-ID in shortcut doesn't match the caller");
+ }
}
private void verifyShortcutInfoPackages(
@@ -1913,11 +1918,32 @@ public class ShortcutService extends IShortcutService.Stub {
}
if (shortcut.getIcon() != null) {
ShortcutInfo.validateIcon(shortcut.getIcon());
+ validateIconURI(shortcut);
}
shortcut.replaceFlags(shortcut.getFlags() & ShortcutInfo.FLAG_LONG_LIVED);
}
+ // Validates the calling process has permission to access shortcut icon's image uri
+ private void validateIconURI(@NonNull final ShortcutInfo si) {
+ final int callingUid = injectBinderCallingUid();
+ final Icon icon = si.getIcon();
+ if (icon == null) {
+ // There's no icon in this shortcut, nothing to validate here.
+ return;
+ }
+ int iconType = icon.getType();
+ if (iconType != Icon.TYPE_URI && iconType != Icon.TYPE_URI_ADAPTIVE_BITMAP) {
+ // The icon is not URI-based, nothing to validate.
+ return;
+ }
+ final Uri uri = icon.getUri();
+ mUriGrantsManagerInternal.checkGrantUriPermission(callingUid, si.getPackage(),
+ ContentProvider.getUriWithoutUserId(uri),
+ Intent.FLAG_GRANT_READ_URI_PERMISSION,
+ ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(callingUid)));
+ }
+
private void fixUpIncomingShortcutInfo(@NonNull ShortcutInfo shortcut, boolean forUpdate) {
fixUpIncomingShortcutInfo(shortcut, forUpdate, /*forPinRequest=*/ false);
}
diff --git a/services/core/java/com/android/server/pm/TEST_MAPPING b/services/core/java/com/android/server/pm/TEST_MAPPING
index 9c74dd795d30..9d76072cceeb 100644
--- a/services/core/java/com/android/server/pm/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/TEST_MAPPING
@@ -81,7 +81,7 @@
]
}
],
- "presubmit-large": [
+ "postsubmit": [
{
"name": "CtsContentTestCases",
"options": [
@@ -95,9 +95,7 @@
"include-filter": "android.content.pm.cts"
}
]
- }
- ],
- "postsubmit": [
+ },
{
"name": "CtsPermissionTestCases",
"options": [
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
index b296ef2a1443..1ff01a6c70bf 100644
--- a/services/core/java/com/android/server/vr/VrManagerService.java
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -1049,7 +1049,11 @@ public class VrManagerService extends SystemService
for (ComponentName c : possibleServices) {
if (Objects.equals(c.getPackageName(), pkg)) {
- nm.setNotificationListenerAccessGrantedForUser(c, userId, true);
+ try {
+ nm.setNotificationListenerAccessGrantedForUser(c, userId, true);
+ } catch (Exception e) {
+ Slog.w(TAG, "Could not grant NLS access to package " + pkg, e);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index ec9babf09ef3..4633e34f78f6 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1946,7 +1946,8 @@ class ActivityStarter {
// If Activity's launching into PiP, move the mStartActivity immediately to pinned mode.
// Note that mStartActivity and source should be in the same Task at this point.
if (mOptions != null && mOptions.isLaunchIntoPip()
- && sourceRecord != null && sourceRecord.getTask() == mStartActivity.getTask()) {
+ && sourceRecord != null && sourceRecord.getTask() == mStartActivity.getTask()
+ && !mRestrictedBgActivity) {
mRootWindowContainer.moveActivityToPinnedRootTask(mStartActivity,
sourceRecord, "launch-into-pip");
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index aa154292fe7e..71ca8523ce71 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -18,6 +18,7 @@ package com.android.server.wm;
import static android.Manifest.permission.BIND_VOICE_INTERACTION;
import static android.Manifest.permission.CHANGE_CONFIGURATION;
+import static android.Manifest.permission.CONTROL_KEYGUARD;
import static android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS;
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
@@ -3394,6 +3395,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
@Override
public void keyguardGoingAway(int flags) {
+ mAmInternal.enforceCallingPermission(CONTROL_KEYGUARD, "unlock keyguard");
enforceNotIsolatedCaller("keyguardGoingAway");
final long token = Binder.clearCallingIdentity();
try {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 4c32edc6d709..8a14c93c1d38 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -3604,12 +3604,20 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// apps won't always be considered as foreground state.
// Exclude private presentations as they can only be shown on private virtual displays and
// shouldn't be the cause of an app be considered foreground.
- if (mAttrs.type >= FIRST_SYSTEM_WINDOW && mAttrs.type != TYPE_TOAST
- && mAttrs.type != TYPE_PRIVATE_PRESENTATION) {
+ // Exclude presentations on virtual displays as they are not actually visible.
+ if (mAttrs.type >= FIRST_SYSTEM_WINDOW
+ && mAttrs.type != TYPE_TOAST
+ && mAttrs.type != TYPE_PRIVATE_PRESENTATION
+ && !(mAttrs.type == TYPE_PRESENTATION && isOnVirtualDisplay())
+ ) {
mWmService.mAtmService.mActiveUids.onNonAppSurfaceVisibilityChanged(mOwnerUid, shown);
}
}
+ private boolean isOnVirtualDisplay() {
+ return getDisplayContent().mDisplay.getType() == Display.TYPE_VIRTUAL;
+ }
+
private void logExclusionRestrictions(int side) {
if (!logsGestureExclusionRestrictions(this)
|| SystemClock.uptimeMillis() < mLastExclusionLogUptimeMillis[side]
diff --git a/services/print/java/com/android/server/print/PrintManagerService.java b/services/print/java/com/android/server/print/PrintManagerService.java
index 66524edf61ed..1386bbff6cab 100644
--- a/services/print/java/com/android/server/print/PrintManagerService.java
+++ b/services/print/java/com/android/server/print/PrintManagerService.java
@@ -254,12 +254,45 @@ public final class PrintManagerService extends SystemService {
}
final long identity = Binder.clearCallingIdentity();
try {
- return userState.getCustomPrinterIcon(printerId);
+ Icon icon = userState.getCustomPrinterIcon(printerId);
+ return validateIconUserBoundary(icon);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
+ /**
+ * Validates the custom printer icon to see if it's not in the calling user space.
+ * If the condition is not met, return null. Otherwise, return the original icon.
+ *
+ * @param icon
+ * @return icon (validated)
+ */
+ private Icon validateIconUserBoundary(Icon icon) {
+ // Refer to Icon#getUriString for context. The URI string is invalid for icons of
+ // incompatible types.
+ if (icon != null && (icon.getType() == Icon.TYPE_URI
+ || icon.getType() == Icon.TYPE_URI_ADAPTIVE_BITMAP)) {
+ String encodedUser = icon.getUri().getEncodedUserInfo();
+
+ // If there is no encoded user, the URI is calling into the calling user space
+ if (encodedUser != null) {
+ int userId = Integer.parseInt(encodedUser);
+ // resolve encoded user
+ final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+
+ synchronized (mLock) {
+ // Only the current group members can get the printer icons.
+ if (resolveCallingProfileParentLocked(resolvedUserId)
+ != getCurrentUserId()) {
+ return null;
+ }
+ }
+ }
+ }
+ return icon;
+ }
+
@Override
public void cancelPrintJob(PrintJobId printJobId, int appId, int userId) {
if (printJobId == null) {
diff --git a/services/tests/PackageManagerServiceTests/server/res/raw/install_app1_cert5 b/services/tests/PackageManagerServiceTests/server/res/raw/install_app1_cert5
index 138b6113ea6b..3683dca64449 100644
--- a/services/tests/PackageManagerServiceTests/server/res/raw/install_app1_cert5
+++ b/services/tests/PackageManagerServiceTests/server/res/raw/install_app1_cert5
Binary files differ
diff --git a/services/tests/PackageManagerServiceTests/server/res/raw/install_app1_cert5_rotated_cert6 b/services/tests/PackageManagerServiceTests/server/res/raw/install_app1_cert5_rotated_cert6
index 2da2436d9b16..c2418bec1505 100644
--- a/services/tests/PackageManagerServiceTests/server/res/raw/install_app1_cert5_rotated_cert6
+++ b/services/tests/PackageManagerServiceTests/server/res/raw/install_app1_cert5_rotated_cert6
Binary files differ
diff --git a/services/tests/PackageManagerServiceTests/server/res/raw/install_app2_cert5_rotated_cert6 b/services/tests/PackageManagerServiceTests/server/res/raw/install_app2_cert5_rotated_cert6
index 30bb6478d18d..6feebb8c833c 100644
--- a/services/tests/PackageManagerServiceTests/server/res/raw/install_app2_cert5_rotated_cert6
+++ b/services/tests/PackageManagerServiceTests/server/res/raw/install_app2_cert5_rotated_cert6
Binary files differ
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/PackageManagerTests.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/PackageManagerTests.java
index d288d41ae96c..8707a4f77845 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/PackageManagerTests.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/PackageManagerTests.java
@@ -56,7 +56,7 @@ import android.os.Process;
import android.os.RemoteException;
import android.os.StatFs;
import android.os.SystemClock;
-import android.platform.test.annotations.Presubmit;
+import android.platform.test.annotations.Postsubmit;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import android.system.ErrnoException;
@@ -94,7 +94,7 @@ import java.util.concurrent.CountDownLatch;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;
-@Presubmit
+@Postsubmit
public class PackageManagerTests extends AndroidTestCase {
private static final boolean localLOGV = true;
@@ -197,10 +197,11 @@ public class PackageManagerTests extends AndroidTestCase {
}
public Intent getResult() {
- try {
- return mResult.take();
- } catch (InterruptedException e) {
- throw new RuntimeException(e);
+ while (true) {
+ try {
+ return mResult.take();
+ } catch (InterruptedException e) {
+ }
}
}
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 28480bcda4eb..8c60178f44fe 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -79,6 +79,7 @@ import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.fail;
+import static org.junit.Assert.assertThrows;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyLong;
@@ -3725,6 +3726,30 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
+ public void testSetListenerAccessForUser_grantWithNameTooLong_throws() {
+ UserHandle user = UserHandle.of(mContext.getUserId() + 10);
+ ComponentName c = new ComponentName("com.example.package",
+ com.google.common.base.Strings.repeat("Blah", 150));
+
+ assertThrows(IllegalArgumentException.class,
+ () -> mBinderService.setNotificationListenerAccessGrantedForUser(
+ c, user.getIdentifier(), /* enabled= */ true, true));
+ }
+
+ @Test
+ public void testSetListenerAccessForUser_revokeWithNameTooLong_okay() throws Exception {
+ UserHandle user = UserHandle.of(mContext.getUserId() + 10);
+ ComponentName c = new ComponentName("com.example.package",
+ com.google.common.base.Strings.repeat("Blah", 150));
+
+ mBinderService.setNotificationListenerAccessGrantedForUser(
+ c, user.getIdentifier(), /* enabled= */ false, true);
+
+ verify(mListeners).setPackageOrComponentEnabled(
+ c.flattenToString(), user.getIdentifier(), true, /* enabled= */ false, true);
+ }
+
+ @Test
public void testSetAssistantAccessForUser() throws Exception {
UserInfo ui = new UserInfo();
ui.id = mContext.getUserId() + 10;
@@ -5205,6 +5230,13 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
.addExtras(extras)
.build();
+ // Serialize and deserialize the notification to make sure nothing breaks in the process,
+ // since that's what will usually happen before we get to call visitUris.
+ Parcel parcel = Parcel.obtain();
+ n.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ n = new Notification(parcel);
+
Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class);
n.visitUris(visitor);
verify(visitor, times(1)).accept(eq(audioContents));
@@ -5324,6 +5356,69 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
+ public void testVisitUris_styleExtrasWithoutStyle() {
+ Notification notification = new Notification.Builder(mContext, "a")
+ .setSmallIcon(android.R.drawable.sym_def_app_icon)
+ .build();
+
+ Notification.MessagingStyle messagingStyle = new Notification.MessagingStyle(
+ personWithIcon("content://user"))
+ .addHistoricMessage(new Notification.MessagingStyle.Message("Heyhey!",
+ System.currentTimeMillis(),
+ personWithIcon("content://historicalMessenger")))
+ .addMessage(new Notification.MessagingStyle.Message("Are you there",
+ System.currentTimeMillis(),
+ personWithIcon("content://messenger")))
+ .setShortcutIcon(
+ Icon.createWithContentUri("content://conversationShortcut"));
+ messagingStyle.addExtras(notification.extras); // Instead of Builder.setStyle(style).
+
+ Notification.CallStyle callStyle = Notification.CallStyle.forOngoingCall(
+ personWithIcon("content://caller"),
+ PendingIntent.getActivity(mContext, 0, new Intent(),
+ PendingIntent.FLAG_IMMUTABLE))
+ .setVerificationIcon(Icon.createWithContentUri("content://callVerification"));
+ callStyle.addExtras(notification.extras); // Same.
+
+ Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class);
+ notification.visitUris(visitor);
+
+ verify(visitor).accept(eq(Uri.parse("content://user")));
+ verify(visitor).accept(eq(Uri.parse("content://historicalMessenger")));
+ verify(visitor).accept(eq(Uri.parse("content://messenger")));
+ verify(visitor).accept(eq(Uri.parse("content://conversationShortcut")));
+ verify(visitor).accept(eq(Uri.parse("content://caller")));
+ verify(visitor).accept(eq(Uri.parse("content://callVerification")));
+ }
+
+ private static Person personWithIcon(String iconUri) {
+ return new Person.Builder()
+ .setName("Mr " + iconUri)
+ .setIcon(Icon.createWithContentUri(iconUri))
+ .build();
+ }
+
+ @Test
+ public void testVisitUris_wearableExtender() {
+ Icon actionIcon = Icon.createWithContentUri("content://media/action");
+ Icon wearActionIcon = Icon.createWithContentUri("content://media/wearAction");
+ PendingIntent intent = PendingIntent.getActivity(mContext, 0, new Intent(),
+ PendingIntent.FLAG_IMMUTABLE);
+ Notification n = new Notification.Builder(mContext, "a")
+ .setSmallIcon(android.R.drawable.sym_def_app_icon)
+ .addAction(new Notification.Action.Builder(actionIcon, "Hey!", intent).build())
+ .extend(new Notification.WearableExtender().addAction(
+ new Notification.Action.Builder(wearActionIcon, "Wear!", intent).build()))
+ .build();
+
+ Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class);
+ n.visitUris(visitor);
+
+ verify(visitor).accept(eq(actionIcon.getUri()));
+ verify(visitor).accept(eq(wearActionIcon.getUri()));
+ }
+
+ @Test
public void testSetNotificationPolicy_preP_setOldFields() {
ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class);
mService.mZenModeHelper = mZenModeHelper;
diff --git a/services/usb/OWNERS b/services/usb/OWNERS
index 60172a36128e..d35dbb56437b 100644
--- a/services/usb/OWNERS
+++ b/services/usb/OWNERS
@@ -1,3 +1,7 @@
+aprasath@google.com
+kumarashishg@google.com
+sarup@google.com
+anothermark@google.com
badhri@google.com
elaurent@google.com
albertccwang@google.com
diff --git a/telecomm/java/android/telecom/ParcelableConference.java b/telecomm/java/android/telecom/ParcelableConference.java
index e57c833e930e..6dcfa6d56ef3 100644
--- a/telecomm/java/android/telecom/ParcelableConference.java
+++ b/telecomm/java/android/telecom/ParcelableConference.java
@@ -21,12 +21,12 @@ import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
+import com.android.internal.telecom.IVideoProvider;
+
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
-import com.android.internal.telecom.IVideoProvider;
-
/**
* A parcelable representation of a conference connection.
* @hide
@@ -287,6 +287,14 @@ public final class ParcelableConference implements Parcelable {
return mCallDirection;
}
+ public String getCallerDisplayName() {
+ return mCallerDisplayName;
+ }
+
+ public int getCallerDisplayNamePresentation() {
+ return mCallerDisplayNamePresentation;
+ }
+
public static final @android.annotation.NonNull Parcelable.Creator<ParcelableConference> CREATOR =
new Parcelable.Creator<ParcelableConference> () {
@Override
diff --git a/telecomm/java/android/telecom/StatusHints.java b/telecomm/java/android/telecom/StatusHints.java
index 2faecc2e3468..5f0c8d729e74 100644
--- a/telecomm/java/android/telecom/StatusHints.java
+++ b/telecomm/java/android/telecom/StatusHints.java
@@ -16,14 +16,19 @@
package android.telecom;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.content.ComponentName;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
+import android.os.Binder;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.UserHandle;
+
+import com.android.internal.annotations.VisibleForTesting;
import java.util.Objects;
@@ -33,7 +38,7 @@ import java.util.Objects;
public final class StatusHints implements Parcelable {
private final CharSequence mLabel;
- private final Icon mIcon;
+ private Icon mIcon;
private final Bundle mExtras;
/**
@@ -48,11 +53,31 @@ public final class StatusHints implements Parcelable {
public StatusHints(CharSequence label, Icon icon, Bundle extras) {
mLabel = label;
- mIcon = icon;
+ mIcon = validateAccountIconUserBoundary(icon, Binder.getCallingUserHandle());
mExtras = extras;
}
/**
+ * @param icon
+ * @hide
+ */
+ @VisibleForTesting
+ public StatusHints(@Nullable Icon icon) {
+ mLabel = null;
+ mExtras = null;
+ mIcon = icon;
+ }
+
+ /**
+ *
+ * @param icon
+ * @hide
+ */
+ public void setIcon(@Nullable Icon icon) {
+ mIcon = icon;
+ }
+
+ /**
* @return A package used to load the icon.
*
* @hide
@@ -112,6 +137,30 @@ public final class StatusHints implements Parcelable {
return 0;
}
+ /**
+ * Validates the StatusHints image icon to see if it's not in the calling user space.
+ * Invalidates the icon if so, otherwise returns back the original icon.
+ *
+ * @param icon
+ * @return icon (validated)
+ * @hide
+ */
+ public static Icon validateAccountIconUserBoundary(Icon icon, UserHandle callingUserHandle) {
+ // Refer to Icon#getUriString for context. The URI string is invalid for icons of
+ // incompatible types.
+ if (icon != null && (icon.getType() == Icon.TYPE_URI
+ || icon.getType() == Icon.TYPE_URI_ADAPTIVE_BITMAP)) {
+ String encodedUser = icon.getUri().getEncodedUserInfo();
+ // If there is no encoded user, the URI is calling into the calling user space
+ if (encodedUser != null) {
+ int userId = Integer.parseInt(encodedUser);
+ // Do not try to save the icon if the user id isn't in the calling user space.
+ if (userId != callingUserHandle.getIdentifier()) return null;
+ }
+ }
+ return icon;
+ }
+
@Override
public void writeToParcel(Parcel out, int flags) {
out.writeCharSequence(mLabel);