diff options
| author | 2022-12-31 02:20:33 +0000 | |
|---|---|---|
| committer | 2022-12-31 02:20:33 +0000 | |
| commit | b4f33e803046ff932f062a13867e8c0351ecd200 (patch) | |
| tree | 2d7382e0393920c81c8dad2f07186d2530427d74 | |
| parent | fef67ba1cf6adffc56d009d0f88cf820f7f06cb1 (diff) | |
| parent | ab90ee56c3fce4bc7c9a2981acdae3d842b4cf01 (diff) | |
Snap for 9446458 from ab90ee56c3fce4bc7c9a2981acdae3d842b4cf01 to tm-qpr2-release
Change-Id: Ia5e5757c87f079fbfd3141ad1a78175551b199d1
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, ""); } } } |