diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java index b32358643efb3..ae7a671f3d54c 100644 --- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java +++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java @@ -154,6 +154,28 @@ public class LogModule { return factory.create("SwipeStatusBarAwayLog", 30); } + /** + * Provides a logging buffer for logs related to the media tap-to-transfer chip on the sender + * device. See {@link com.android.systemui.media.taptotransfer.sender.MediaTttSenderLogger}. + */ + @Provides + @SysUISingleton + @MediaTttSenderLogBuffer + public static LogBuffer provideMediaTttSenderLogBuffer(LogBufferFactory factory) { + return factory.create("MediaTttSender", 20); + } + + /** + * Provides a logging buffer for logs related to the media tap-to-transfer chip on the receiver + * device. See {@link com.android.systemui.media.taptotransfer.receiver.MediaTttReceiverLogger}. + */ + @Provides + @SysUISingleton + @MediaTttReceiverLogBuffer + public static LogBuffer provideMediaTttReceiverLogBuffer(LogBufferFactory factory) { + return factory.create("MediaTttReceiver", 20); + } + /** Allows logging buffers to be tweaked via adb on debug builds but not on prod builds. */ @Provides @SysUISingleton diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/MediaTttReceiverLogBuffer.java b/packages/SystemUI/src/com/android/systemui/log/dagger/MediaTttReceiverLogBuffer.java new file mode 100644 index 0000000000000..5c572e8ef554e --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/log/dagger/MediaTttReceiverLogBuffer.java @@ -0,0 +1,36 @@ +/* + * 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.dagger; + +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import com.android.systemui.log.LogBuffer; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; + +import javax.inject.Qualifier; + +/** + * A {@link LogBuffer} for + * {@link com.android.systemui.media.taptotransfer.receiver.MediaTttReceiverLogger}. + */ +@Qualifier +@Documented +@Retention(RUNTIME) +public @interface MediaTttReceiverLogBuffer { +} diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/MediaTttSenderLogBuffer.java b/packages/SystemUI/src/com/android/systemui/log/dagger/MediaTttSenderLogBuffer.java new file mode 100644 index 0000000000000..edab8c319f879 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/log/dagger/MediaTttSenderLogBuffer.java @@ -0,0 +1,36 @@ +/* + * 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.dagger; + +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import com.android.systemui.log.LogBuffer; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; + +import javax.inject.Qualifier; + +/** + * A {@link LogBuffer} for + * {@link com.android.systemui.media.taptotransfer.sender.MediaTttSenderLogger}. + */ +@Qualifier +@Documented +@Retention(RUNTIME) +public @interface MediaTttSenderLogBuffer { +} diff --git a/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java b/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java index c3b4354ebabe3..66c036cee6009 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java +++ b/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java @@ -17,6 +17,9 @@ package com.android.systemui.media.dagger; import com.android.systemui.dagger.SysUISingleton; +import com.android.systemui.log.LogBuffer; +import com.android.systemui.log.dagger.MediaTttReceiverLogBuffer; +import com.android.systemui.log.dagger.MediaTttSenderLogBuffer; import com.android.systemui.media.MediaDataManager; import com.android.systemui.media.MediaFlags; import com.android.systemui.media.MediaHierarchyManager; @@ -27,8 +30,11 @@ import com.android.systemui.media.muteawait.MediaMuteAwaitConnectionCli; import com.android.systemui.media.nearby.NearbyMediaDevicesManager; import com.android.systemui.media.taptotransfer.MediaTttCommandLineHelper; import com.android.systemui.media.taptotransfer.MediaTttFlags; +import com.android.systemui.media.taptotransfer.common.MediaTttLogger; import com.android.systemui.media.taptotransfer.receiver.MediaTttChipControllerReceiver; +import com.android.systemui.media.taptotransfer.receiver.MediaTttReceiverLogger; import com.android.systemui.media.taptotransfer.sender.MediaTttChipControllerSender; +import com.android.systemui.media.taptotransfer.sender.MediaTttSenderLogger; import java.util.Optional; @@ -112,6 +118,24 @@ public interface MediaModule { return Optional.of(controllerReceiverLazy.get()); } + @Provides + @SysUISingleton + @MediaTttSenderLogger + static MediaTttLogger providesMediaTttSenderLogger( + @MediaTttSenderLogBuffer LogBuffer buffer + ) { + return new MediaTttLogger("Sender", buffer); + } + + @Provides + @SysUISingleton + @MediaTttReceiverLogger + static MediaTttLogger providesMediaTttReceiverLogger( + @MediaTttReceiverLogBuffer LogBuffer buffer + ) { + return new MediaTttLogger("Receiver", buffer); + } + /** */ @Provides @SysUISingleton diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt index 15b8f13ee0f89..59607c4b6e31f 100644 --- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt @@ -43,6 +43,7 @@ import com.android.systemui.util.view.ViewUtil */ abstract class MediaTttChipControllerCommon( internal val context: Context, + internal val logger: MediaTttLogger, private val windowManager: WindowManager, private val viewUtil: ViewUtil, @Main private val mainExecutor: DelayableExecutor, @@ -93,18 +94,29 @@ abstract class MediaTttChipControllerCommon( // Cancel and re-set the chip timeout each time we get a new state. cancelChipViewTimeout?.run() - cancelChipViewTimeout = mainExecutor.executeDelayed(this::removeChip, TIMEOUT_MILLIS) + cancelChipViewTimeout = mainExecutor.executeDelayed( + { removeChip(REASON_TIMEOUT) }, + TIMEOUT_MILLIS + ) } - /** Hides the chip. */ - fun removeChip() { + /** + * Hides the chip. + * + * @param removalReason a short string describing why the chip was removed (timeout, state + * change, etc.) + */ + fun removeChip(removalReason: String) { // TODO(b/203800347): We may not want to hide the chip if we're currently in a // TransferTriggered state: Once the user has initiated the transfer, they should be able // to move away from the receiver device but still see the status of the transfer. if (chipView == null) { return } + logger.logChipRemoval(removalReason) tapGestureDetector.removeOnGestureDetectedCallback(TAG) windowManager.removeView(chipView) chipView = null + // No need to time the chip out since it's already gone + cancelChipViewTimeout?.run() } /** @@ -136,7 +148,7 @@ abstract class MediaTttChipControllerCommon( // If the tap is within the chip bounds, we shouldn't hide the chip (in case users think the // chip is tappable). if (!viewUtil.touchIsWithinView(view, e.x, e.y)) { - removeChip() + removeChip(REASON_SCREEN_TAP) } } } @@ -147,3 +159,6 @@ private const val WINDOW_TITLE = "Media Transfer Chip View" private val TAG = MediaTttChipControllerCommon::class.simpleName!! @VisibleForTesting const val TIMEOUT_MILLIS = 3000L + +private const val REASON_TIMEOUT = "TIMEOUT" +private const val REASON_SCREEN_TAP = "SCREEN_TAP" diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttLogger.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttLogger.kt new file mode 100644 index 0000000000000..d3b5bc62b0e1a --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttLogger.kt @@ -0,0 +1,56 @@ +/* + * 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.media.taptotransfer.common + +import com.android.systemui.log.LogBuffer +import com.android.systemui.log.LogLevel +import com.android.systemui.log.dagger.MediaTttSenderLogBuffer + +/** + * A logger for media tap-to-transfer events. + * + * @property deviceTypeTag the type of device triggering the logs -- "Sender" or "Receiver". + */ +class MediaTttLogger( + private val deviceTypeTag: String, + @MediaTttSenderLogBuffer private val buffer: LogBuffer +){ + /** Logs a change in the chip state for the given [mediaRouteId]. */ + fun logStateChange(stateName: String, mediaRouteId: String) { + buffer.log( + BASE_TAG + deviceTypeTag, + LogLevel.DEBUG, + { + str1 = stateName + str2 = mediaRouteId + }, + { "State changed to $str1 for ID=$str2" } + ) + } + + /** Logs that we removed the chip for the given [reason]. */ + fun logChipRemoval(reason: String) { + buffer.log( + BASE_TAG + deviceTypeTag, + LogLevel.DEBUG, + { str1 = reason }, + { "Chip removed due to $str1" } + ) + } +} + +private const val BASE_TAG = "MediaTtt" diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt index 3d43ebe817428..1a96ddf69b284 100644 --- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt @@ -28,6 +28,7 @@ import com.android.systemui.R import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.media.taptotransfer.common.MediaTttChipControllerCommon +import com.android.systemui.media.taptotransfer.common.MediaTttLogger import com.android.systemui.statusbar.CommandQueue import com.android.systemui.statusbar.gesture.TapGestureDetector import com.android.systemui.util.concurrency.DelayableExecutor @@ -43,6 +44,7 @@ import javax.inject.Inject class MediaTttChipControllerReceiver @Inject constructor( commandQueue: CommandQueue, context: Context, + @MediaTttReceiverLogger logger: MediaTttLogger, windowManager: WindowManager, viewUtil: ViewUtil, mainExecutor: DelayableExecutor, @@ -50,6 +52,7 @@ class MediaTttChipControllerReceiver @Inject constructor( @Main private val mainHandler: Handler, ) : MediaTttChipControllerCommon( context, + logger, windowManager, viewUtil, mainExecutor, @@ -79,6 +82,7 @@ class MediaTttChipControllerReceiver @Inject constructor( appIcon: Icon?, appName: CharSequence? ) { + logger.logStateChange(stateIntToString(displayState), routeInfo.id) when(displayState) { StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_CLOSE_TO_SENDER -> { val packageName = routeInfo.packageName @@ -97,7 +101,8 @@ class MediaTttChipControllerReceiver @Inject constructor( ) } } - StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_FAR_FROM_SENDER -> removeChip() + StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_FAR_FROM_SENDER -> + removeChip(removalReason = FAR_FROM_SENDER) else -> Log.e(RECEIVER_TAG, "Unhandled MediaTransferReceiverState $displayState") } @@ -106,6 +111,16 @@ class MediaTttChipControllerReceiver @Inject constructor( override fun updateChipView(chipState: ChipStateReceiver, currentChipView: ViewGroup) { setIcon(chipState, currentChipView) } + + private fun stateIntToString(@StatusBarManager.MediaTransferReceiverState state: Int): String { + return when (state) { + StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_CLOSE_TO_SENDER -> CLOSE_TO_SENDER + StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_FAR_FROM_SENDER -> FAR_FROM_SENDER + else -> "INVALID: $state" + } + } } private const val RECEIVER_TAG = "MediaTapToTransferRcvr" +private const val CLOSE_TO_SENDER = "CLOSE_TO_SENDER" +private const val FAR_FROM_SENDER = "FAR_FROM_SENDER" diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverLogger.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverLogger.kt new file mode 100644 index 0000000000000..54fc48ddba910 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverLogger.kt @@ -0,0 +1,26 @@ +/* + * 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.media.taptotransfer.receiver + +import java.lang.annotation.Documented +import java.lang.annotation.Retention +import java.lang.annotation.RetentionPolicy +import javax.inject.Qualifier + +@Qualifier +@Documented +@Retention(RetentionPolicy.RUNTIME) +annotation class MediaTttReceiverLogger diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt index 180e4ee9726c2..5737b15323cd9 100644 --- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt @@ -29,6 +29,7 @@ import com.android.systemui.R import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.media.taptotransfer.common.MediaTttChipControllerCommon +import com.android.systemui.media.taptotransfer.common.MediaTttLogger import com.android.systemui.statusbar.CommandQueue import com.android.systemui.statusbar.gesture.TapGestureDetector import com.android.systemui.util.concurrency.DelayableExecutor @@ -43,12 +44,19 @@ import javax.inject.Inject class MediaTttChipControllerSender @Inject constructor( commandQueue: CommandQueue, context: Context, + @MediaTttSenderLogger logger: MediaTttLogger, windowManager: WindowManager, viewUtil: ViewUtil, @Main mainExecutor: DelayableExecutor, tapGestureDetector: TapGestureDetector, ) : MediaTttChipControllerCommon( - context, windowManager, viewUtil, mainExecutor, tapGestureDetector, R.layout.media_ttt_chip + context, + logger, + windowManager, + viewUtil, + mainExecutor, + tapGestureDetector, + R.layout.media_ttt_chip ) { private val commandQueueCallbacks = object : CommandQueue.Callbacks { override fun updateMediaTapToTransferSenderDisplay( @@ -71,6 +79,7 @@ class MediaTttChipControllerSender @Inject constructor( routeInfo: MediaRoute2Info, undoCallback: IUndoMediaTransferCallback? ) { + logger.logStateChange(stateIntToString(displayState), routeInfo.id) val appPackageName = routeInfo.packageName val otherDeviceName = routeInfo.name.toString() val chipState = when(displayState) { @@ -90,7 +99,7 @@ class MediaTttChipControllerSender @Inject constructor( StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_FAILED -> TransferFailed(appPackageName) StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER -> { - removeChip() + removeChip(removalReason = FAR_FROM_RECEIVER) null } else -> { @@ -129,6 +138,31 @@ class MediaTttChipControllerSender @Inject constructor( currentChipView.requireViewById(R.id.failure_icon).visibility = if (showFailure) { View.VISIBLE } else { View.GONE } } + + private fun stateIntToString(@StatusBarManager.MediaTransferSenderState state: Int): String { + return when(state) { + StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST -> + "ALMOST_CLOSE_TO_START_CAST" + StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_END_CAST -> + "ALMOST_CLOSE_TO_END_CAST" + StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_TRIGGERED -> + "TRANSFER_TO_RECEIVER_TRIGGERED" + StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_TRIGGERED -> + "TRANSFER_TO_THIS_DEVICE_TRIGGERED" + StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED -> + "TRANSFER_TO_RECEIVER_SUCCEEDED" + StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_SUCCEEDED -> + "TRANSFER_TO_THIS_DEVICE_SUCCEEDED" + StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_FAILED -> + "TRANSFER_TO_RECEIVER_FAILED" + StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_FAILED -> + "TRANSFER_TO_THIS_DEVICE_FAILED" + StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER -> + FAR_FROM_RECEIVER + else -> "INVALID: $state" + } + } } const val SENDER_TAG = "MediaTapToTransferSender" +private const val FAR_FROM_RECEIVER = "FAR_FROM_RECEIVER" diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderLogger.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderLogger.kt new file mode 100644 index 0000000000000..4393af9a99ecf --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderLogger.kt @@ -0,0 +1,26 @@ +/* + * 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.media.taptotransfer.sender + +import java.lang.annotation.Documented +import java.lang.annotation.Retention +import java.lang.annotation.RetentionPolicy +import javax.inject.Qualifier + +@Qualifier +@Documented +@Retention(RetentionPolicy.RUNTIME) +annotation class MediaTttSenderLogger diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt index 809b8901f8675..62bb2ce70acad 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt @@ -55,6 +55,8 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() { private lateinit var appIconDrawable: Drawable @Mock + private lateinit var logger: MediaTttLogger + @Mock private lateinit var windowManager: WindowManager @Mock private lateinit var viewUtil: ViewUtil @@ -69,7 +71,7 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() { fakeExecutor = FakeExecutor(fakeClock) controllerCommon = TestControllerCommon( - context, windowManager, viewUtil, fakeExecutor, tapGestureDetector + context, logger, windowManager, viewUtil, fakeExecutor, tapGestureDetector ) } @@ -145,20 +147,22 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() { } @Test - fun removeChip_chipRemovedAndGestureDetectionStopped() { + fun removeChip_chipRemovedAndGestureDetectionStoppedAndRemovalLogged() { // First, add the chip controllerCommon.displayChip(getState()) // Then, remove it - controllerCommon.removeChip() + val reason = "test reason" + controllerCommon.removeChip(reason) verify(windowManager).removeView(any()) verify(tapGestureDetector).removeOnGestureDetectedCallback(any()) + verify(logger).logChipRemoval(reason) } @Test fun removeChip_noAdd_viewNotRemoved() { - controllerCommon.removeChip() + controllerCommon.removeChip("reason") verify(windowManager, never()).removeView(any()) } @@ -222,12 +226,19 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() { inner class TestControllerCommon( context: Context, + logger: MediaTttLogger, windowManager: WindowManager, viewUtil: ViewUtil, @Main mainExecutor: DelayableExecutor, tapGestureDetector: TapGestureDetector, ) : MediaTttChipControllerCommon( - context, windowManager, viewUtil, mainExecutor, tapGestureDetector, R.layout.media_ttt_chip + context, + logger, + windowManager, + viewUtil, + mainExecutor, + tapGestureDetector, + R.layout.media_ttt_chip ) { override fun updateChipView(chipState: MediaTttChipState, currentChipView: ViewGroup) { } diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttLoggerTest.kt new file mode 100644 index 0000000000000..d95e5c48256c0 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttLoggerTest.kt @@ -0,0 +1,75 @@ +/* + * 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.media.taptotransfer.common + +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.dump.DumpManager +import com.android.systemui.log.LogBuffer +import com.android.systemui.log.LogBufferFactory +import com.android.systemui.log.LogcatEchoTracker +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Test +import org.mockito.Mockito.mock +import java.io.PrintWriter +import java.io.StringWriter + +@SmallTest +class MediaTttLoggerTest : SysuiTestCase() { + + private lateinit var buffer: LogBuffer + private lateinit var logger: MediaTttLogger + + @Before + fun setUp () { + buffer = LogBufferFactory(DumpManager(), mock(LogcatEchoTracker::class.java)) + .create("buffer", 10) + logger = MediaTttLogger(DEVICE_TYPE_TAG, buffer) + } + + @Test + fun logStateChange_bufferHasDeviceTypeTagAndStateNameAndId() { + val stateName = "test state name" + val id = "test id" + + logger.logStateChange(stateName, id) + + val stringWriter = StringWriter() + buffer.dump(PrintWriter(stringWriter), tailLength = 0) + val actualString = stringWriter.toString() + + assertThat(actualString).contains(DEVICE_TYPE_TAG) + assertThat(actualString).contains(stateName) + assertThat(actualString).contains(id) + } + + @Test + fun logChipRemoval_bufferHasDeviceTypeAndReason() { + val reason = "test reason" + logger.logChipRemoval(reason) + + val stringWriter = StringWriter() + buffer.dump(PrintWriter(stringWriter), tailLength = 0) + val actualString = stringWriter.toString() + + assertThat(actualString).contains(DEVICE_TYPE_TAG) + assertThat(actualString).contains(reason) + } +} + +private const val DEVICE_TYPE_TAG = "TEST TYPE" diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt index 86d4c1b05ed33..56f45896436c5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt @@ -31,6 +31,7 @@ import android.widget.ImageView import androidx.test.filters.SmallTest import com.android.systemui.R import com.android.systemui.SysuiTestCase +import com.android.systemui.media.taptotransfer.common.MediaTttLogger import com.android.systemui.statusbar.CommandQueue import com.android.systemui.statusbar.gesture.TapGestureDetector import com.android.systemui.util.concurrency.FakeExecutor @@ -60,6 +61,8 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() { @Mock private lateinit var applicationInfo: ApplicationInfo @Mock + private lateinit var logger: MediaTttLogger + @Mock private lateinit var windowManager: WindowManager @Mock private lateinit var viewUtil: ViewUtil @@ -83,6 +86,7 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() { controllerReceiver = MediaTttChipControllerReceiver( commandQueue, context, + logger, windowManager, viewUtil, FakeExecutor(FakeSystemClock()), @@ -141,6 +145,18 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() { verify(windowManager).removeView(viewCaptor.value) } + @Test + fun receivesNewStateFromCommandQueue_isLogged() { + commandQueueCallback.updateMediaTapToTransferReceiverDisplay( + StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_CLOSE_TO_SENDER, + routeInfo, + null, + null + ) + + verify(logger).logStateChange(any(), any()) + } + @Test fun displayChip_nullAppIconDrawable_iconIsFromPackageName() { val state = ChipStateReceiver(PACKAGE_NAME, appIconDrawable = null, "appName") diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt index 88888f0da0f76..367e2e462d955 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt @@ -32,6 +32,7 @@ import androidx.test.filters.SmallTest import com.android.internal.statusbar.IUndoMediaTransferCallback import com.android.systemui.R import com.android.systemui.SysuiTestCase +import com.android.systemui.media.taptotransfer.common.MediaTttLogger import com.android.systemui.statusbar.CommandQueue import com.android.systemui.statusbar.gesture.TapGestureDetector import com.android.systemui.util.concurrency.FakeExecutor @@ -62,6 +63,8 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() { @Mock private lateinit var applicationInfo: ApplicationInfo @Mock + private lateinit var logger: MediaTttLogger + @Mock private lateinit var windowManager: WindowManager @Mock private lateinit var viewUtil: ViewUtil @@ -85,6 +88,7 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() { controllerSender = MediaTttChipControllerSender( commandQueue, context, + logger, windowManager, viewUtil, FakeExecutor(FakeSystemClock()), @@ -222,6 +226,17 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() { verify(windowManager).removeView(viewCaptor.value) } + @Test + fun receivesNewStateFromCommandQueue_isLogged() { + commandQueueCallback.updateMediaTapToTransferSenderDisplay( + StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST, + routeInfo, + null + ) + + verify(logger).logStateChange(any(), any()) + } + @Test fun almostCloseToStartCast_appIcon_deviceName_noLoadingIcon_noUndo_noFailureIcon() { val state = almostCloseToStartCast()