summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Android Build Coastguard Worker <android-build-coastguard-worker@google.com> 2022-12-31 02:20:33 +0000
committer Android Build Coastguard Worker <android-build-coastguard-worker@google.com> 2022-12-31 02:20:33 +0000
commitb4f33e803046ff932f062a13867e8c0351ecd200 (patch)
tree2d7382e0393920c81c8dad2f07186d2530427d74
parentfef67ba1cf6adffc56d009d0f88cf820f7f06cb1 (diff)
parentab90ee56c3fce4bc7c9a2981acdae3d842b4cf01 (diff)
Snap for 9446458 from ab90ee56c3fce4bc7c9a2981acdae3d842b4cf01 to tm-qpr2-release
Change-Id: Ia5e5757c87f079fbfd3141ad1a78175551b199d1
-rw-r--r--media/java/android/media/session/ISession.aidl2
-rw-r--r--media/java/android/media/session/MediaSession.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/Flags.kt3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/log/table/LogDiffsForTableTest.kt1081
-rw-r--r--services/core/java/com/android/server/media/MediaButtonReceiverHolder.java61
-rw-r--r--services/core/java/com/android/server/media/MediaSessionRecord.java5
-rw-r--r--services/core/java/com/android/server/media/MediaSessionService.java6
7 files changed, 1127 insertions, 33 deletions
diff --git a/media/java/android/media/session/ISession.aidl b/media/java/android/media/session/ISession.aidl
index 9bf126b7a875..31fb8d03c4a0 100644
--- a/media/java/android/media/session/ISession.aidl
+++ b/media/java/android/media/session/ISession.aidl
@@ -35,7 +35,7 @@ interface ISession {
ISessionController getController();
void setFlags(int flags);
void setActive(boolean active);
- void setMediaButtonReceiver(in PendingIntent mbr, String sessionPackageName);
+ void setMediaButtonReceiver(in PendingIntent mbr);
void setMediaButtonBroadcastReceiver(in ComponentName broadcastReceiver);
void setLaunchPendingIntent(in PendingIntent pi);
void destroySession();
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index bc00c404b11e..84ecc06d172f 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -286,7 +286,7 @@ public final class MediaSession {
@Deprecated
public void setMediaButtonReceiver(@Nullable PendingIntent mbr) {
try {
- mBinder.setMediaButtonReceiver(mbr, mContext.getPackageName());
+ mBinder.setMediaButtonReceiver(mbr);
} catch (RemoteException e) {
Log.wtf(TAG, "Failure in setMediaButtonReceiver.", e);
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index dbeef8d2383b..8cd734ccc7ae 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -413,6 +413,9 @@ object Flags {
val WM_ENABLE_PREDICTIVE_BACK_SYSUI =
unreleasedFlag(1204, "persist.wm.debug.predictive_back_sysui_enable", teamfood = true)
+ // TODO(b/255697805): Tracking Bug
+ @JvmField val TRACKPAD_GESTURE_BACK = unreleasedFlag(1205, "trackpad_gesture_back", teamfood = false)
+
// 1300 - screenshots
// TODO(b/254512719): Tracking Bug
@JvmField val SCREENSHOT_REQUEST_PROCESSOR = releasedFlag(1300, "screenshot_request_processor")
diff --git a/packages/SystemUI/tests/src/com/android/systemui/log/table/LogDiffsForTableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/log/table/LogDiffsForTableTest.kt
new file mode 100644
index 000000000000..3b5e6b9c145c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/log/table/LogDiffsForTableTest.kt
@@ -0,0 +1,1081 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.log.table
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.time.FakeSystemClock
+import com.google.common.truth.Truth.assertThat
+import java.io.PrintWriter
+import java.io.StringWriter
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.collect
+import kotlinx.coroutines.flow.flow
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+
+@SmallTest
+@OptIn(ExperimentalCoroutinesApi::class)
+class LogDiffsForTableTest : SysuiTestCase() {
+
+ private val testScope = TestScope(UnconfinedTestDispatcher())
+
+ private lateinit var systemClock: FakeSystemClock
+ private lateinit var tableLogBuffer: TableLogBuffer
+
+ @Before
+ fun setUp() {
+ systemClock = FakeSystemClock()
+ tableLogBuffer = TableLogBuffer(MAX_SIZE, BUFFER_NAME, systemClock)
+ }
+
+ // ---- Flow<Boolean> tests ----
+
+ @Test
+ fun boolean_doesNotLogWhenNotCollected() {
+ val flow = flowOf(true, true, false)
+
+ flow.logDiffsForTable(
+ tableLogBuffer,
+ COLUMN_PREFIX,
+ COLUMN_NAME,
+ initialValue = false,
+ )
+
+ val logs = dumpLog()
+ assertThat(logs).doesNotContain(COLUMN_PREFIX)
+ assertThat(logs).doesNotContain(COLUMN_NAME)
+ assertThat(logs).doesNotContain("false")
+ }
+
+ @Test
+ fun boolean_logsInitialWhenCollected() =
+ testScope.runTest {
+ val flow = flowOf(true, true, false)
+
+ val flowWithLogging =
+ flow.logDiffsForTable(
+ tableLogBuffer,
+ COLUMN_PREFIX,
+ COLUMN_NAME,
+ initialValue = false,
+ )
+
+ systemClock.setCurrentTimeMillis(3000L)
+ val job = launch { flowWithLogging.collect() }
+
+ val logs = dumpLog()
+ assertThat(logs)
+ .contains(
+ TABLE_LOG_DATE_FORMAT.format(3000L) +
+ SEPARATOR +
+ FULL_NAME +
+ SEPARATOR +
+ "false"
+ )
+
+ job.cancel()
+ }
+
+ @Test
+ fun boolean_logsUpdates() =
+ testScope.runTest {
+ systemClock.setCurrentTimeMillis(100L)
+ val flow = flow {
+ for (bool in listOf(true, false, true)) {
+ systemClock.advanceTime(100L)
+ emit(bool)
+ }
+ }
+
+ val flowWithLogging =
+ flow.logDiffsForTable(
+ tableLogBuffer,
+ COLUMN_PREFIX,
+ COLUMN_NAME,
+ initialValue = false,
+ )
+
+ val job = launch { flowWithLogging.collect() }
+
+ val logs = dumpLog()
+ assertThat(logs)
+ .contains(
+ TABLE_LOG_DATE_FORMAT.format(100L) + SEPARATOR + FULL_NAME + SEPARATOR + "false"
+ )
+ assertThat(logs)
+ .contains(
+ TABLE_LOG_DATE_FORMAT.format(200L) + SEPARATOR + FULL_NAME + SEPARATOR + "true"
+ )
+ assertThat(logs)
+ .contains(
+ TABLE_LOG_DATE_FORMAT.format(300L) + SEPARATOR + FULL_NAME + SEPARATOR + "false"
+ )
+ assertThat(logs)
+ .contains(
+ TABLE_LOG_DATE_FORMAT.format(400L) + SEPARATOR + FULL_NAME + SEPARATOR + "true"
+ )
+
+ job.cancel()
+ }
+
+ @Test
+ fun boolean_doesNotLogIfSameValue() =
+ testScope.runTest {
+ systemClock.setCurrentTimeMillis(100L)
+ val flow = flow {
+ for (bool in listOf(true, true, false, false, true)) {
+ systemClock.advanceTime(100L)
+ emit(bool)
+ }
+ }
+
+ val flowWithLogging =
+ flow.logDiffsForTable(
+ tableLogBuffer,
+ COLUMN_PREFIX,
+ COLUMN_NAME,
+ initialValue = true,
+ )
+
+ val job = launch { flowWithLogging.collect() }
+
+ val logs = dumpLog()
+ // Input flow: true@100, true@200, true@300, false@400, false@500, true@600
+ // Output log: true@100, --------, --------, false@400, ---------, true@600
+ val expected1 =
+ TABLE_LOG_DATE_FORMAT.format(100L) + SEPARATOR + FULL_NAME + SEPARATOR + "true"
+ val expected4 =
+ TABLE_LOG_DATE_FORMAT.format(400L) + SEPARATOR + FULL_NAME + SEPARATOR + "false"
+ val expected6 =
+ TABLE_LOG_DATE_FORMAT.format(600L) + SEPARATOR + FULL_NAME + SEPARATOR + "true"
+ assertThat(logs).contains(expected1)
+ assertThat(logs).contains(expected4)
+ assertThat(logs).contains(expected6)
+
+ val unexpected2 =
+ TABLE_LOG_DATE_FORMAT.format(200L) + SEPARATOR + FULL_NAME + SEPARATOR + "true"
+ val unexpected3 =
+ TABLE_LOG_DATE_FORMAT.format(300L) + SEPARATOR + FULL_NAME + SEPARATOR + "true"
+ val unexpected5 =
+ TABLE_LOG_DATE_FORMAT.format(500L) + SEPARATOR + FULL_NAME + SEPARATOR + "false"
+ assertThat(logs).doesNotContain(unexpected2)
+ assertThat(logs).doesNotContain(unexpected3)
+ assertThat(logs).doesNotContain(unexpected5)
+
+ job.cancel()
+ }
+
+ @Test
+ fun boolean_worksForStateFlows() =
+ testScope.runTest {
+ val flow = MutableStateFlow(false)
+
+ val flowWithLogging =
+ flow.logDiffsForTable(
+ tableLogBuffer,
+ COLUMN_PREFIX,
+ COLUMN_NAME,
+ initialValue = false,
+ )
+
+ systemClock.setCurrentTimeMillis(50L)
+ val job = launch { flowWithLogging.collect() }
+ assertThat(dumpLog())
+ .contains(
+ TABLE_LOG_DATE_FORMAT.format(50L) + SEPARATOR + FULL_NAME + SEPARATOR + "false"
+ )
+
+ systemClock.setCurrentTimeMillis(100L)
+ flow.emit(true)
+ assertThat(dumpLog())
+ .contains(
+ TABLE_LOG_DATE_FORMAT.format(100L) + SEPARATOR + FULL_NAME + SEPARATOR + "true"
+ )
+
+ systemClock.setCurrentTimeMillis(200L)
+ flow.emit(false)
+ assertThat(dumpLog())
+ .contains(
+ TABLE_LOG_DATE_FORMAT.format(200L) + SEPARATOR + FULL_NAME + SEPARATOR + "false"
+ )
+
+ // Doesn't log duplicates
+ systemClock.setCurrentTimeMillis(300L)
+ flow.emit(false)
+ assertThat(dumpLog())
+ .doesNotContain(
+ TABLE_LOG_DATE_FORMAT.format(300L) + SEPARATOR + FULL_NAME + SEPARATOR + "false"
+ )
+
+ job.cancel()
+ }
+
+ // ---- Flow<Int> tests ----
+
+ @Test
+ fun int_doesNotLogWhenNotCollected() {
+ val flow = flowOf(5, 6, 7)
+
+ flow.logDiffsForTable(
+ tableLogBuffer,
+ COLUMN_PREFIX,
+ COLUMN_NAME,
+ initialValue = 1234,
+ )
+
+ val logs = dumpLog()
+ assertThat(logs).doesNotContain(COLUMN_PREFIX)
+ assertThat(logs).doesNotContain(COLUMN_NAME)
+ assertThat(logs).doesNotContain("1234")
+ }
+
+ @Test
+ fun int_logsInitialWhenCollected() =
+ testScope.runTest {
+ val flow = flowOf(5, 6, 7)
+
+ val flowWithLogging =
+ flow.logDiffsForTable(
+ tableLogBuffer,
+ COLUMN_PREFIX,
+ COLUMN_NAME,
+ initialValue = 1234,
+ )
+
+ systemClock.setCurrentTimeMillis(3000L)
+ val job = launch { flowWithLogging.collect() }
+
+ val logs = dumpLog()
+ assertThat(logs)
+ .contains(
+ TABLE_LOG_DATE_FORMAT.format(3000L) + SEPARATOR + FULL_NAME + SEPARATOR + "1234"
+ )
+
+ job.cancel()
+ }
+
+ @Test
+ fun int_logsUpdates() =
+ testScope.runTest {
+ systemClock.setCurrentTimeMillis(100L)
+ val flow = flow {
+ for (int in listOf(2, 3, 4)) {
+ systemClock.advanceTime(100L)
+ emit(int)
+ }
+ }
+
+ val flowWithLogging =
+ flow.logDiffsForTable(
+ tableLogBuffer,
+ COLUMN_PREFIX,
+ COLUMN_NAME,
+ initialValue = 1,
+ )
+
+ val job = launch { flowWithLogging.collect() }
+
+ val logs = dumpLog()
+ assertThat(logs)
+ .contains(
+ TABLE_LOG_DATE_FORMAT.format(100L) + SEPARATOR + FULL_NAME + SEPARATOR + "1"
+ )
+ assertThat(logs)
+ .contains(
+ TABLE_LOG_DATE_FORMAT.format(200L) + SEPARATOR + FULL_NAME + SEPARATOR + "2"
+ )
+ assertThat(logs)
+ .contains(
+ TABLE_LOG_DATE_FORMAT.format(300L) + SEPARATOR + FULL_NAME + SEPARATOR + "3"
+ )
+ assertThat(logs)
+ .contains(
+ TABLE_LOG_DATE_FORMAT.format(400L) + SEPARATOR + FULL_NAME + SEPARATOR + "4"
+ )
+
+ job.cancel()
+ }
+
+ @Test
+ fun int_doesNotLogIfSameValue() =
+ testScope.runTest {
+ systemClock.setCurrentTimeMillis(100L)
+ val flow = flow {
+ for (bool in listOf(2, 3, 3, 3, 2, 6, 6)) {
+ systemClock.advanceTime(100L)
+ emit(bool)
+ }
+ }
+
+ val flowWithLogging =
+ flow.logDiffsForTable(
+ tableLogBuffer,
+ COLUMN_PREFIX,
+ COLUMN_NAME,
+ initialValue = 1,
+ )
+
+ val job = launch { flowWithLogging.collect() }
+
+ val logs = dumpLog()
+ // Input flow: 1@100, 2@200, 3@300, 3@400, 3@500, 2@600, 6@700, 6@800
+ // Output log: 1@100, 2@200, 3@300, -----, -----, 2@600, 6@700, -----
+ val expected1 =
+ TABLE_LOG_DATE_FORMAT.format(100L) + SEPARATOR + FULL_NAME + SEPARATOR + "1"
+ val expected2 =
+ TABLE_LOG_DATE_FORMAT.format(200L) + SEPARATOR + FULL_NAME + SEPARATOR + "2"
+ val expected3 =
+ TABLE_LOG_DATE_FORMAT.format(300L) + SEPARATOR + FULL_NAME + SEPARATOR + "3"
+ val expected6 =
+ TABLE_LOG_DATE_FORMAT.format(600L) + SEPARATOR + FULL_NAME + SEPARATOR + "2"
+ val expected7 =
+ TABLE_LOG_DATE_FORMAT.format(700L) + SEPARATOR + FULL_NAME + SEPARATOR + "6"
+ assertThat(logs).contains(expected1)
+ assertThat(logs).contains(expected2)
+ assertThat(logs).contains(expected3)
+ assertThat(logs).contains(expected6)
+ assertThat(logs).contains(expected7)
+
+ val unexpected4 =
+ TABLE_LOG_DATE_FORMAT.format(400L) + SEPARATOR + FULL_NAME + SEPARATOR + "3"
+ val unexpected5 =
+ TABLE_LOG_DATE_FORMAT.format(500L) + SEPARATOR + FULL_NAME + SEPARATOR + "3"
+ val unexpected8 =
+ TABLE_LOG_DATE_FORMAT.format(800L) + SEPARATOR + FULL_NAME + SEPARATOR + "6"
+ assertThat(logs).doesNotContain(unexpected4)
+ assertThat(logs).doesNotContain(unexpected5)
+ assertThat(logs).doesNotContain(unexpected8)
+ job.cancel()
+ }
+
+ @Test
+ fun int_worksForStateFlows() =
+ testScope.runTest {
+ val flow = MutableStateFlow(1111)
+
+ val flowWithLogging =
+ flow.logDiffsForTable(
+ tableLogBuffer,
+ COLUMN_PREFIX,
+ COLUMN_NAME,
+ initialValue = 1111,
+ )
+
+ systemClock.setCurrentTimeMillis(50L)
+ val job = launch { flowWithLogging.collect() }
+ assertThat(dumpLog())
+ .contains(
+ TABLE_LOG_DATE_FORMAT.format(50L) + SEPARATOR + FULL_NAME + SEPARATOR + "1111"
+ )
+
+ systemClock.setCurrentTimeMillis(100L)
+ flow.emit(2222)
+ assertThat(dumpLog())
+ .contains(
+ TABLE_LOG_DATE_FORMAT.format(100L) + SEPARATOR + FULL_NAME + SEPARATOR + "2222"
+ )
+
+ systemClock.setCurrentTimeMillis(200L)
+ flow.emit(3333)
+ assertThat(dumpLog())
+ .contains(
+ TABLE_LOG_DATE_FORMAT.format(200L) + SEPARATOR + FULL_NAME + SEPARATOR + "3333"
+ )
+
+ // Doesn't log duplicates
+ systemClock.setCurrentTimeMillis(300L)
+ flow.emit(3333)
+ assertThat(dumpLog())
+ .doesNotContain(
+ TABLE_LOG_DATE_FORMAT.format(300L) + SEPARATOR + FULL_NAME + SEPARATOR + "3333"
+ )
+
+ job.cancel()
+ }
+
+ // ---- Flow<String> tests ----
+
+ @Test
+ fun string_doesNotLogWhenNotCollected() {
+ val flow = flowOf("val5", "val6", "val7")
+
+ flow.logDiffsForTable(
+ tableLogBuffer,
+ COLUMN_PREFIX,
+ COLUMN_NAME,
+ initialValue = "val1234",
+ )
+
+ val logs = dumpLog()
+ assertThat(logs).doesNotContain(COLUMN_PREFIX)
+ assertThat(logs).doesNotContain(COLUMN_NAME)
+ assertThat(logs).doesNotContain("val1234")
+ }
+
+ @Test
+ fun string_logsInitialWhenCollected() =
+ testScope.runTest {
+ val flow = flowOf("val5", "val6", "val7")
+
+ val flowWithLogging =
+ flow.logDiffsForTable(
+ tableLogBuffer,
+ COLUMN_PREFIX,
+ COLUMN_NAME,
+ initialValue = "val1234",
+ )
+
+ systemClock.setCurrentTimeMillis(3000L)
+ val job = launch { flowWithLogging.collect() }
+
+ val logs = dumpLog()
+ assertThat(logs)
+ .contains(
+ TABLE_LOG_DATE_FORMAT.format(3000L) +
+ SEPARATOR +
+ FULL_NAME +
+ SEPARATOR +
+ "val1234"
+ )
+
+ job.cancel()
+ }
+
+ @Test
+ fun string_logsUpdates() =
+ testScope.runTest {
+ systemClock.setCurrentTimeMillis(100L)
+ val flow = flow {
+ for (int in listOf("val2", "val3", "val4")) {
+ systemClock.advanceTime(100L)
+ emit(int)
+ }
+ }
+
+ val flowWithLogging =
+ flow.logDiffsForTable(
+ tableLogBuffer,
+ COLUMN_PREFIX,
+ COLUMN_NAME,
+ initialValue = "val1",
+ )
+
+ val job = launch { flowWithLogging.collect() }
+
+ val logs = dumpLog()
+ assertThat(logs)
+ .contains(
+ TABLE_LOG_DATE_FORMAT.format(100L) + SEPARATOR + FULL_NAME + SEPARATOR + "val1"
+ )
+ assertThat(logs)
+ .contains(
+ TABLE_LOG_DATE_FORMAT.format(200L) + SEPARATOR + FULL_NAME + SEPARATOR + "val2"
+ )
+ assertThat(logs)
+ .contains(
+ TABLE_LOG_DATE_FORMAT.format(300L) + SEPARATOR + FULL_NAME + SEPARATOR + "val3"
+ )
+ assertThat(logs)
+ .contains(
+ TABLE_LOG_DATE_FORMAT.format(400L) + SEPARATOR + FULL_NAME + SEPARATOR + "val4"
+ )
+
+ job.cancel()
+ }
+
+ @Test
+ fun string_logsNull() =
+ testScope.runTest {
+ systemClock.setCurrentTimeMillis(100L)
+ val flow = flow {
+ for (int in listOf(null, "something", null)) {
+ systemClock.advanceTime(100L)
+ emit(int)
+ }
+ }
+
+ val flowWithLogging =
+ flow.logDiffsForTable(
+ tableLogBuffer,
+ COLUMN_PREFIX,
+ COLUMN_NAME,
+ initialValue = "start",
+ )
+
+ val job = launch { flowWithLogging.collect() }
+
+ val logs = dumpLog()
+ assertThat(logs)
+ .contains(
+ TABLE_LOG_DATE_FORMAT.format(100L) + SEPARATOR + FULL_NAME + SEPARATOR + "start"
+ )
+ assertThat(logs)
+ .contains(
+ TABLE_LOG_DATE_FORMAT.format(200L) + SEPARATOR + FULL_NAME + SEPARATOR + "null"
+ )
+ assertThat(logs)
+ .contains(
+ TABLE_LOG_DATE_FORMAT.format(300L) +
+ SEPARATOR +
+ FULL_NAME +
+ SEPARATOR +
+ "something"
+ )
+ assertThat(logs)
+ .contains(
+ TABLE_LOG_DATE_FORMAT.format(400L) + SEPARATOR + FULL_NAME + SEPARATOR + "null"
+ )
+
+ job.cancel()
+ }
+
+ @Test
+ fun string_doesNotLogIfSameValue() =
+ testScope.runTest {
+ systemClock.setCurrentTimeMillis(100L)
+ val flow = flow {
+ for (bool in listOf("start", "new", "new", "newer", "newest", "newest")) {
+ systemClock.advanceTime(100L)
+ emit(bool)
+ }
+ }
+
+ val flowWithLogging =
+ flow.logDiffsForTable(
+ tableLogBuffer,
+ COLUMN_PREFIX,
+ COLUMN_NAME,
+ initialValue = "start",
+ )
+
+ val job = launch { flowWithLogging.collect() }
+
+ val logs = dumpLog()
+ // Input flow: start@100, start@200, new@300, new@400, newer@500, newest@600, newest@700
+ // Output log: start@100, ---------, new@300, -------, newer@500, newest@600, ----------
+ val expected1 =
+ TABLE_LOG_DATE_FORMAT.format(100L) + SEPARATOR + FULL_NAME + SEPARATOR + "start"
+ val expected3 =
+ TABLE_LOG_DATE_FORMAT.format(300L) + SEPARATOR + FULL_NAME + SEPARATOR + "new"
+ val expected5 =
+ TABLE_LOG_DATE_FORMAT.format(500L) + SEPARATOR + FULL_NAME + SEPARATOR + "newer"
+ val expected6 =
+ TABLE_LOG_DATE_FORMAT.format(600L) + SEPARATOR + FULL_NAME + SEPARATOR + "newest"
+ assertThat(logs).contains(expected1)
+ assertThat(logs).contains(expected3)
+ assertThat(logs).contains(expected5)
+ assertThat(logs).contains(expected6)
+
+ val unexpected2 =
+ TABLE_LOG_DATE_FORMAT.format(200L) + SEPARATOR + FULL_NAME + SEPARATOR + "start"
+ val unexpected4 =
+ TABLE_LOG_DATE_FORMAT.format(400L) + SEPARATOR + FULL_NAME + SEPARATOR + "new"
+ val unexpected7 =
+ TABLE_LOG_DATE_FORMAT.format(700L) + SEPARATOR + FULL_NAME + SEPARATOR + "newest"
+ assertThat(logs).doesNotContain(unexpected2)
+ assertThat(logs).doesNotContain(unexpected4)
+ assertThat(logs).doesNotContain(unexpected7)
+
+ job.cancel()
+ }
+
+ @Test
+ fun string_worksForStateFlows() =
+ testScope.runTest {
+ val flow = MutableStateFlow("initial")
+
+ val flowWithLogging =
+ flow.logDiffsForTable(
+ tableLogBuffer,
+ COLUMN_PREFIX,
+ COLUMN_NAME,
+ initialValue = "initial",
+ )
+
+ systemClock.setCurrentTimeMillis(50L)
+ val job = launch { flowWithLogging.collect() }
+ assertThat(dumpLog())
+ .contains(
+ TABLE_LOG_DATE_FORMAT.format(50L) +
+ SEPARATOR +
+ FULL_NAME +
+ SEPARATOR +
+ "initial"
+ )
+
+ systemClock.setCurrentTimeMillis(100L)
+ flow.emit("nextVal")
+ assertThat(dumpLog())
+ .contains(
+ TABLE_LOG_DATE_FORMAT.format(100L) +
+ SEPARATOR +
+ FULL_NAME +
+ SEPARATOR +
+ "nextVal"
+ )
+
+ systemClock.setCurrentTimeMillis(200L)
+ flow.emit("nextNextVal")
+ assertThat(dumpLog())
+ .contains(
+ TABLE_LOG_DATE_FORMAT.format(200L) +
+ SEPARATOR +
+ FULL_NAME +
+ SEPARATOR +
+ "nextNextVal"
+ )
+
+ // Doesn't log duplicates
+ systemClock.setCurrentTimeMillis(300L)
+ flow.emit("nextNextVal")
+ assertThat(dumpLog())
+ .doesNotContain(
+ TABLE_LOG_DATE_FORMAT.format(300L) +
+ SEPARATOR +
+ FULL_NAME +
+ SEPARATOR +
+ "nextNextVal"
+ )
+
+ job.cancel()
+ }
+
+ // ---- Flow<Diffable> tests ----
+
+ @Test
+ fun diffable_doesNotLogWhenNotCollected() {
+ val flow =
+ flowOf(
+ TestDiffable(1, "1", true),
+ TestDiffable(2, "2", false),
+ )
+
+ val initial = TestDiffable(0, "0", false)
+ flow.logDiffsForTable(
+ tableLogBuffer,
+ COLUMN_PREFIX,
+ initial,
+ )
+
+ val logs = dumpLog()
+ assertThat(logs).doesNotContain(COLUMN_PREFIX)
+ assertThat(logs).doesNotContain(TestDiffable.COL_FULL)
+ assertThat(logs).doesNotContain(TestDiffable.COL_INT)
+ assertThat(logs).doesNotContain(TestDiffable.COL_STRING)
+ assertThat(logs).doesNotContain(TestDiffable.COL_BOOLEAN)
+ }
+
+ @Test
+ fun diffable_logsInitialWhenCollected_usingLogFull() =
+ testScope.runTest {
+ val flow =
+ flowOf(
+ TestDiffable(1, "1", true),
+ TestDiffable(2, "2", false),
+ )
+
+ val initial = TestDiffable(1234, "string1234", false)
+ val flowWithLogging =
+ flow.logDiffsForTable(
+ tableLogBuffer,
+ COLUMN_PREFIX,
+ initial,
+ )
+
+ systemClock.setCurrentTimeMillis(3000L)
+ val job = launch { flowWithLogging.collect() }
+
+ val logs = dumpLog()
+ assertThat(logs)
+ .contains(
+ TABLE_LOG_DATE_FORMAT.format(3000L) +
+ SEPARATOR +
+ COLUMN_PREFIX +
+ "." +
+ TestDiffable.COL_FULL +
+ SEPARATOR +
+ "true"
+ )
+ assertThat(logs)
+ .contains(
+ TABLE_LOG_DATE_FORMAT.format(3000L) +
+ SEPARATOR +
+ COLUMN_PREFIX +
+ "." +
+ TestDiffable.COL_INT +
+ SEPARATOR +
+ "1234"
+ )
+ assertThat(logs)
+ .contains(
+ TABLE_LOG_DATE_FORMAT.format(3000L) +
+ SEPARATOR +
+ COLUMN_PREFIX +
+ "." +
+ TestDiffable.COL_STRING +
+ SEPARATOR +
+ "string1234"
+ )
+ assertThat(logs)
+ .contains(
+ TABLE_LOG_DATE_FORMAT.format(3000L) +
+ SEPARATOR +
+ COLUMN_PREFIX +
+ "." +
+ TestDiffable.COL_BOOLEAN +
+ SEPARATOR +
+ "false"
+ )
+ job.cancel()
+ }
+
+ @Test
+ fun diffable_logsUpdates_usingLogDiffs() =
+ testScope.runTest {
+ val initialValue = TestDiffable(0, "string0", false)
+ val diffables =
+ listOf(
+ TestDiffable(1, "string1", true),
+ TestDiffable(2, "string1", true),
+ TestDiffable(2, "string2", false),
+ )
+
+ systemClock.setCurrentTimeMillis(100L)
+ val flow = flow {
+ for (diffable in diffables) {
+ systemClock.advanceTime(100L)
+ emit(diffable)
+ }
+ }
+
+ val flowWithLogging =
+ flow.logDiffsForTable(
+ tableLogBuffer,
+ COLUMN_PREFIX,
+ initialValue,
+ )
+
+ val job = launch { flowWithLogging.collect() }
+
+ val logs = dumpLog()
+
+ // Initial -> first: everything different
+ assertThat(logs)
+ .contains(
+ TABLE_LOG_DATE_FORMAT.format(200L) +
+ SEPARATOR +
+ COLUMN_PREFIX +
+ "." +
+ TestDiffable.COL_FULL +
+ SEPARATOR +
+ "false"
+ )
+ assertThat(logs)
+ .contains(
+ TABLE_LOG_DATE_FORMAT.format(200L) +
+ SEPARATOR +
+ COLUMN_PREFIX +
+ "." +
+ TestDiffable.COL_INT +
+ SEPARATOR +
+ "1"
+ )
+ assertThat(logs)
+ .contains(
+ TABLE_LOG_DATE_FORMAT.format(200L) +
+ SEPARATOR +
+ COLUMN_PREFIX +
+ "." +
+ TestDiffable.COL_STRING +
+ SEPARATOR +
+ "string1"
+ )
+ assertThat(logs)
+ .contains(
+ TABLE_LOG_DATE_FORMAT.format(200L) +
+ SEPARATOR +
+ COLUMN_PREFIX +
+ "." +
+ TestDiffable.COL_BOOLEAN +
+ SEPARATOR +
+ "true"
+ )
+
+ // First -> second: int different
+ assertThat(logs)
+ .contains(
+ TABLE_LOG_DATE_FORMAT.format(300L) +
+ SEPARATOR +
+ COLUMN_PREFIX +
+ "." +
+ TestDiffable.COL_FULL +
+ SEPARATOR +
+ "false"
+ )
+ assertThat(logs)
+ .contains(
+ TABLE_LOG_DATE_FORMAT.format(300L) +
+ SEPARATOR +
+ COLUMN_PREFIX +
+ "." +
+ TestDiffable.COL_INT +
+ SEPARATOR +
+ "2"
+ )
+ assertThat(logs)
+ .doesNotContain(
+ TABLE_LOG_DATE_FORMAT.format(300L) +
+ SEPARATOR +
+ COLUMN_PREFIX +
+ "." +
+ TestDiffable.COL_STRING +
+ SEPARATOR +
+ "string1"
+ )
+ assertThat(logs)
+ .doesNotContain(
+ TABLE_LOG_DATE_FORMAT.format(300L) +
+ SEPARATOR +
+ COLUMN_PREFIX +
+ "." +
+ TestDiffable.COL_BOOLEAN +
+ SEPARATOR +
+ "true"
+ )
+
+ // Second -> third: string & boolean different
+ assertThat(logs)
+ .contains(
+ TABLE_LOG_DATE_FORMAT.format(400L) +
+ SEPARATOR +
+ COLUMN_PREFIX +
+ "." +
+ TestDiffable.COL_FULL +
+ SEPARATOR +
+ "false"
+ )
+ assertThat(logs)
+ .contains(
+ TABLE_LOG_DATE_FORMAT.format(400L) +
+ SEPARATOR +
+ COLUMN_PREFIX +
+ "." +
+ TestDiffable.COL_STRING +
+ SEPARATOR +
+ "string2"
+ )
+ assertThat(logs)
+ .contains(
+ TABLE_LOG_DATE_FORMAT.format(400L) +
+ SEPARATOR +
+ COLUMN_PREFIX +
+ "." +
+ TestDiffable.COL_BOOLEAN +
+ SEPARATOR +
+ "false"
+ )
+ assertThat(logs)
+ .doesNotContain(
+ TABLE_LOG_DATE_FORMAT.format(400L) +
+ SEPARATOR +
+ COLUMN_PREFIX +
+ "." +
+ TestDiffable.COL_INT +
+ SEPARATOR +
+ "2"
+ )
+
+ job.cancel()
+ }
+
+ @Test
+ fun diffable_worksForStateFlows() =
+ testScope.runTest {
+ val initialValue = TestDiffable(0, "string0", false)
+ val flow = MutableStateFlow(initialValue)
+ val flowWithLogging =
+ flow.logDiffsForTable(
+ tableLogBuffer,
+ COLUMN_PREFIX,
+ initialValue,
+ )
+
+ systemClock.setCurrentTimeMillis(50L)
+ val job = launch { flowWithLogging.collect() }
+
+ var logs = dumpLog()
+ assertThat(logs)
+ .contains(
+ TABLE_LOG_DATE_FORMAT.format(50L) +
+ SEPARATOR +
+ COLUMN_PREFIX +
+ "." +
+ TestDiffable.COL_INT +
+ SEPARATOR +
+ "0"
+ )
+ assertThat(logs)
+ .contains(
+ TABLE_LOG_DATE_FORMAT.format(50L) +
+ SEPARATOR +
+ COLUMN_PREFIX +
+ "." +
+ TestDiffable.COL_STRING +
+ SEPARATOR +
+ "string0"
+ )
+ assertThat(logs)
+ .contains(
+ TABLE_LOG_DATE_FORMAT.format(50L) +
+ SEPARATOR +
+ COLUMN_PREFIX +
+ "." +
+ TestDiffable.COL_BOOLEAN +
+ SEPARATOR +
+ "false"
+ )
+
+ systemClock.setCurrentTimeMillis(100L)
+ flow.emit(TestDiffable(1, "string1", true))
+
+ logs = dumpLog()
+ assertThat(logs)
+ .contains(
+ TABLE_LOG_DATE_FORMAT.format(100L) +
+ SEPARATOR +
+ COLUMN_PREFIX +
+ "." +
+ TestDiffable.COL_INT +
+ SEPARATOR +
+ "1"
+ )
+ assertThat(logs)
+ .contains(
+ TABLE_LOG_DATE_FORMAT.format(100L) +
+ SEPARATOR +
+ COLUMN_PREFIX +
+ "." +
+ TestDiffable.COL_STRING +
+ SEPARATOR +
+ "string1"
+ )
+ assertThat(logs)
+ .contains(
+ TABLE_LOG_DATE_FORMAT.format(100L) +
+ SEPARATOR +
+ COLUMN_PREFIX +
+ "." +
+ TestDiffable.COL_BOOLEAN +
+ SEPARATOR +
+ "true"
+ )
+
+ // Doesn't log duplicates
+ systemClock.setCurrentTimeMillis(200L)
+ flow.emit(TestDiffable(1, "newString", true))
+
+ logs = dumpLog()
+ assertThat(logs)
+ .doesNotContain(
+ TABLE_LOG_DATE_FORMAT.format(200L) +
+ SEPARATOR +
+ COLUMN_PREFIX +
+ "." +
+ TestDiffable.COL_INT +
+ SEPARATOR +
+ "1"
+ )
+ assertThat(logs)
+ .contains(
+ TABLE_LOG_DATE_FORMAT.format(200L) +
+ SEPARATOR +
+ COLUMN_PREFIX +
+ "." +
+ TestDiffable.COL_STRING +
+ SEPARATOR +
+ "newString"
+ )
+ assertThat(logs)
+ .doesNotContain(
+ TABLE_LOG_DATE_FORMAT.format(200L) +
+ SEPARATOR +
+ COLUMN_PREFIX +
+ "." +
+ TestDiffable.COL_BOOLEAN +
+ SEPARATOR +
+ "true"
+ )
+
+ job.cancel()
+ }
+
+ private fun dumpLog(): String {
+ val outputWriter = StringWriter()
+ tableLogBuffer.dump(PrintWriter(outputWriter), arrayOf())
+ return outputWriter.toString()
+ }
+
+ class TestDiffable(
+ private val testInt: Int,
+ private val testString: String,
+ private val testBoolean: Boolean,
+ ) : Diffable<TestDiffable> {
+ override fun logDiffs(prevVal: TestDiffable, row: TableRowLogger) {
+ row.logChange(COL_FULL, false)
+
+ if (testInt != prevVal.testInt) {
+ row.logChange(COL_INT, testInt)
+ }
+ if (testString != prevVal.testString) {
+ row.logChange(COL_STRING, testString)
+ }
+ if (testBoolean != prevVal.testBoolean) {
+ row.logChange(COL_BOOLEAN, testBoolean)
+ }
+ }
+
+ override fun logFull(row: TableRowLogger) {
+ row.logChange(COL_FULL, true)
+ row.logChange(COL_INT, testInt)
+ row.logChange(COL_STRING, testString)
+ row.logChange(COL_BOOLEAN, testBoolean)
+ }
+
+ companion object {
+ const val COL_INT = "intColumn"
+ const val COL_STRING = "stringColumn"
+ const val COL_BOOLEAN = "booleanColumn"
+ const val COL_FULL = "loggedFullColumn"
+ }
+ }
+
+ private companion object {
+ const val MAX_SIZE = 50
+ const val BUFFER_NAME = "LogDiffsForTableTest"
+ const val COLUMN_PREFIX = "columnPrefix"
+ const val COLUMN_NAME = "columnName"
+ const val FULL_NAME = "$COLUMN_PREFIX.$COLUMN_NAME"
+ private const val SEPARATOR = "|"
+ }
+}
diff --git a/services/core/java/com/android/server/media/MediaButtonReceiverHolder.java b/services/core/java/com/android/server/media/MediaButtonReceiverHolder.java
index 9a190316f4eb..c5fb5270f841 100644
--- a/services/core/java/com/android/server/media/MediaButtonReceiverHolder.java
+++ b/services/core/java/com/android/server/media/MediaButtonReceiverHolder.java
@@ -18,6 +18,7 @@ package com.android.server.media;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.BroadcastOptions;
import android.app.PendingIntent;
import android.content.ComponentName;
@@ -37,6 +38,7 @@ import android.view.KeyEvent;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.Collections;
import java.util.List;
/**
@@ -102,15 +104,19 @@ final class MediaButtonReceiverHolder {
}
/**
- * Creates a new instance.
+ * Creates a new instance from a {@link PendingIntent}.
+ *
+ * <p>This method assumes the session package name has been validated and effectively belongs to
+ * the media session's owner.
*
- * @param context context
* @param userId userId
- * @param pendingIntent pending intent
- * @return Can be {@code null} if pending intent was null.
+ * @param pendingIntent pending intent that will receive media button events
+ * @param sessionPackageName package name of media session owner
+ * @return {@link MediaButtonReceiverHolder} instance or {@code null} if pending intent was
+ * null.
*/
- public static MediaButtonReceiverHolder create(Context context, int userId,
- PendingIntent pendingIntent, String sessionPackageName) {
+ public static MediaButtonReceiverHolder create(
+ int userId, @Nullable PendingIntent pendingIntent, String sessionPackageName) {
if (pendingIntent == null) {
return null;
}
@@ -312,7 +318,7 @@ final class MediaButtonReceiverHolder {
}
private static ComponentName getComponentName(PendingIntent pendingIntent, int componentType) {
- List<ResolveInfo> resolveInfos = null;
+ List<ResolveInfo> resolveInfos = Collections.emptyList();
switch (componentType) {
case COMPONENT_TYPE_ACTIVITY:
resolveInfos = pendingIntent.queryIntentComponents(
@@ -330,32 +336,37 @@ final class MediaButtonReceiverHolder {
PACKAGE_MANAGER_COMMON_FLAGS | PackageManager.GET_RECEIVERS);
break;
}
- if (resolveInfos != null && !resolveInfos.isEmpty()) {
- return createComponentName(resolveInfos.get(0));
+
+ for (ResolveInfo resolveInfo : resolveInfos) {
+ ComponentInfo componentInfo = getComponentInfo(resolveInfo);
+ if (componentInfo != null && TextUtils.equals(componentInfo.packageName,
+ pendingIntent.getCreatorPackage())
+ && componentInfo.packageName != null && componentInfo.name != null) {
+ return new ComponentName(componentInfo.packageName, componentInfo.name);
+ }
}
+
return null;
}
- private static ComponentName createComponentName(ResolveInfo resolveInfo) {
- if (resolveInfo == null) {
- return null;
- }
- ComponentInfo componentInfo;
+ /**
+ * Retrieves the {@link ComponentInfo} from a {@link ResolveInfo} instance. Similar to {@link
+ * ResolveInfo#getComponentInfo()}, but returns {@code null} if this {@link ResolveInfo} points
+ * to a content provider.
+ *
+ * @param resolveInfo Where to extract the {@link ComponentInfo} from.
+ * @return Either a non-null {@link ResolveInfo#activityInfo} or {@link
+ * ResolveInfo#serviceInfo}. Otherwise {@code null} if {@link ResolveInfo#providerInfo} is
+ * not {@code null}.
+ */
+ private static ComponentInfo getComponentInfo(@NonNull ResolveInfo resolveInfo) {
// Code borrowed from ResolveInfo#getComponentInfo().
if (resolveInfo.activityInfo != null) {
- componentInfo = resolveInfo.activityInfo;
+ return resolveInfo.activityInfo;
} else if (resolveInfo.serviceInfo != null) {
- componentInfo = resolveInfo.serviceInfo;
+ return resolveInfo.serviceInfo;
} else {
- // We're not interested in content provider.
- return null;
- }
- // Code borrowed from ComponentInfo#getComponentName().
- try {
- return new ComponentName(componentInfo.packageName, componentInfo.name);
- } catch (IllegalArgumentException | NullPointerException e) {
- // This may be happen if resolveActivity() end up with matching multiple activities.
- // see PackageManager#resolveActivity().
+ // We're not interested in content providers.
return null;
}
}
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 0785fac17984..1bd50632ccbf 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -938,8 +938,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
}
@Override
- public void setMediaButtonReceiver(PendingIntent pi, String sessionPackageName)
- throws RemoteException {
+ public void setMediaButtonReceiver(PendingIntent pi) throws RemoteException {
final long token = Binder.clearCallingIdentity();
try {
if ((mPolicies & MediaSessionPolicyProvider.SESSION_POLICY_IGNORE_BUTTON_RECEIVER)
@@ -947,7 +946,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
return;
}
mMediaButtonReceiverHolder =
- MediaButtonReceiverHolder.create(mContext, mUserId, pi, sessionPackageName);
+ MediaButtonReceiverHolder.create(mUserId, pi, mPackageName);
mService.onMediaButtonReceiverChanged(MediaSessionRecord.this);
} finally {
Binder.restoreCallingIdentity(token);
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index b89147ea181a..d08150cf0a56 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -2285,9 +2285,9 @@ public class MediaSessionService extends SystemService implements Monitor {
PendingIntent pi = mCustomMediaKeyDispatcher.getMediaButtonReceiver(keyEvent,
uid, asSystemService);
if (pi != null) {
- mediaButtonReceiverHolder = MediaButtonReceiverHolder.create(mContext,
- mCurrentFullUserRecord.mFullUserId, pi,
- /* sessionPackageName= */ "");
+ mediaButtonReceiverHolder =
+ MediaButtonReceiverHolder.create(
+ mCurrentFullUserRecord.mFullUserId, pi, "");
}
}
}