1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.systemui.media.controls.util 18 19 import com.android.internal.logging.InstanceId 20 import com.android.internal.logging.InstanceIdSequence 21 import com.android.internal.logging.UiEvent 22 import com.android.internal.logging.UiEventLogger 23 import com.android.systemui.R 24 import com.android.systemui.dagger.SysUISingleton 25 import com.android.systemui.media.controls.models.player.MediaData 26 import com.android.systemui.media.controls.ui.MediaHierarchyManager 27 import com.android.systemui.media.controls.ui.MediaLocation 28 import java.lang.IllegalArgumentException 29 import javax.inject.Inject 30 31 private const val INSTANCE_ID_MAX = 1 shl 20 32 33 /** A helper class to log events related to the media controls */ 34 @SysUISingleton 35 class MediaUiEventLogger @Inject constructor(private val logger: UiEventLogger) { 36 37 private val instanceIdSequence = InstanceIdSequence(INSTANCE_ID_MAX) 38 39 /** Get a new instance ID for a new media control */ 40 fun getNewInstanceId(): InstanceId { 41 return instanceIdSequence.newInstanceId() 42 } 43 44 fun logActiveMediaAdded( 45 uid: Int, 46 packageName: String, 47 instanceId: InstanceId, 48 playbackLocation: Int 49 ) { 50 val event = 51 when (playbackLocation) { 52 MediaData.PLAYBACK_LOCAL -> MediaUiEvent.LOCAL_MEDIA_ADDED 53 MediaData.PLAYBACK_CAST_LOCAL -> MediaUiEvent.CAST_MEDIA_ADDED 54 MediaData.PLAYBACK_CAST_REMOTE -> MediaUiEvent.REMOTE_MEDIA_ADDED 55 else -> throw IllegalArgumentException("Unknown playback location") 56 } 57 logger.logWithInstanceId(event, uid, packageName, instanceId) 58 } 59 60 fun logPlaybackLocationChange( 61 uid: Int, 62 packageName: String, 63 instanceId: InstanceId, 64 playbackLocation: Int 65 ) { 66 val event = 67 when (playbackLocation) { 68 MediaData.PLAYBACK_LOCAL -> MediaUiEvent.TRANSFER_TO_LOCAL 69 MediaData.PLAYBACK_CAST_LOCAL -> MediaUiEvent.TRANSFER_TO_CAST 70 MediaData.PLAYBACK_CAST_REMOTE -> MediaUiEvent.TRANSFER_TO_REMOTE 71 else -> throw IllegalArgumentException("Unknown playback location") 72 } 73 logger.logWithInstanceId(event, uid, packageName, instanceId) 74 } 75 76 fun logResumeMediaAdded(uid: Int, packageName: String, instanceId: InstanceId) { 77 logger.logWithInstanceId(MediaUiEvent.RESUME_MEDIA_ADDED, uid, packageName, instanceId) 78 } 79 80 fun logActiveConvertedToResume(uid: Int, packageName: String, instanceId: InstanceId) { 81 logger.logWithInstanceId(MediaUiEvent.ACTIVE_TO_RESUME, uid, packageName, instanceId) 82 } 83 84 fun logMediaTimeout(uid: Int, packageName: String, instanceId: InstanceId) { 85 logger.logWithInstanceId(MediaUiEvent.MEDIA_TIMEOUT, uid, packageName, instanceId) 86 } 87 88 fun logMediaRemoved(uid: Int, packageName: String, instanceId: InstanceId) { 89 logger.logWithInstanceId(MediaUiEvent.MEDIA_REMOVED, uid, packageName, instanceId) 90 } 91 92 fun logMediaCarouselPage(position: Int) { 93 // Since this operation is on the carousel, we don't include package information 94 logger.logWithPosition(MediaUiEvent.CAROUSEL_PAGE, 0, null, position) 95 } 96 97 fun logSwipeDismiss() { 98 // Since this operation is on the carousel, we don't include package information 99 logger.log(MediaUiEvent.DISMISS_SWIPE) 100 } 101 102 fun logLongPressOpen(uid: Int, packageName: String, instanceId: InstanceId) { 103 logger.logWithInstanceId(MediaUiEvent.OPEN_LONG_PRESS, uid, packageName, instanceId) 104 } 105 106 fun logLongPressDismiss(uid: Int, packageName: String, instanceId: InstanceId) { 107 logger.logWithInstanceId(MediaUiEvent.DISMISS_LONG_PRESS, uid, packageName, instanceId) 108 } 109 110 fun logLongPressSettings(uid: Int, packageName: String, instanceId: InstanceId) { 111 logger.logWithInstanceId( 112 MediaUiEvent.OPEN_SETTINGS_LONG_PRESS, 113 uid, 114 packageName, 115 instanceId 116 ) 117 } 118 119 fun logCarouselSettings() { 120 // Since this operation is on the carousel, we don't include package information 121 logger.log(MediaUiEvent.OPEN_SETTINGS_CAROUSEL) 122 } 123 124 fun logTapAction(buttonId: Int, uid: Int, packageName: String, instanceId: InstanceId) { 125 val event = 126 when (buttonId) { 127 R.id.actionPlayPause -> MediaUiEvent.TAP_ACTION_PLAY_PAUSE 128 R.id.actionPrev -> MediaUiEvent.TAP_ACTION_PREV 129 R.id.actionNext -> MediaUiEvent.TAP_ACTION_NEXT 130 else -> MediaUiEvent.TAP_ACTION_OTHER 131 } 132 133 logger.logWithInstanceId(event, uid, packageName, instanceId) 134 } 135 136 fun logSeek(uid: Int, packageName: String, instanceId: InstanceId) { 137 logger.logWithInstanceId(MediaUiEvent.ACTION_SEEK, uid, packageName, instanceId) 138 } 139 140 fun logOpenOutputSwitcher(uid: Int, packageName: String, instanceId: InstanceId) { 141 logger.logWithInstanceId(MediaUiEvent.OPEN_OUTPUT_SWITCHER, uid, packageName, instanceId) 142 } 143 144 fun logTapContentView(uid: Int, packageName: String, instanceId: InstanceId) { 145 logger.logWithInstanceId(MediaUiEvent.MEDIA_TAP_CONTENT_VIEW, uid, packageName, instanceId) 146 } 147 148 fun logCarouselPosition(@MediaLocation location: Int) { 149 val event = 150 when (location) { 151 MediaHierarchyManager.LOCATION_QQS -> MediaUiEvent.MEDIA_CAROUSEL_LOCATION_QQS 152 MediaHierarchyManager.LOCATION_QS -> MediaUiEvent.MEDIA_CAROUSEL_LOCATION_QS 153 MediaHierarchyManager.LOCATION_LOCKSCREEN -> 154 MediaUiEvent.MEDIA_CAROUSEL_LOCATION_LOCKSCREEN 155 MediaHierarchyManager.LOCATION_DREAM_OVERLAY -> 156 MediaUiEvent.MEDIA_CAROUSEL_LOCATION_DREAM 157 else -> throw IllegalArgumentException("Unknown media carousel location $location") 158 } 159 logger.log(event) 160 } 161 162 fun logRecommendationAdded(packageName: String, instanceId: InstanceId) { 163 logger.logWithInstanceId( 164 MediaUiEvent.MEDIA_RECOMMENDATION_ADDED, 165 0, 166 packageName, 167 instanceId 168 ) 169 } 170 171 fun logRecommendationRemoved(packageName: String, instanceId: InstanceId) { 172 logger.logWithInstanceId( 173 MediaUiEvent.MEDIA_RECOMMENDATION_REMOVED, 174 0, 175 packageName, 176 instanceId 177 ) 178 } 179 180 fun logRecommendationActivated(uid: Int, packageName: String, instanceId: InstanceId) { 181 logger.logWithInstanceId( 182 MediaUiEvent.MEDIA_RECOMMENDATION_ACTIVATED, 183 uid, 184 packageName, 185 instanceId 186 ) 187 } 188 189 fun logRecommendationItemTap(packageName: String, instanceId: InstanceId, position: Int) { 190 logger.logWithInstanceIdAndPosition( 191 MediaUiEvent.MEDIA_RECOMMENDATION_ITEM_TAP, 192 0, 193 packageName, 194 instanceId, 195 position 196 ) 197 } 198 199 fun logRecommendationCardTap(packageName: String, instanceId: InstanceId) { 200 logger.logWithInstanceId( 201 MediaUiEvent.MEDIA_RECOMMENDATION_CARD_TAP, 202 0, 203 packageName, 204 instanceId 205 ) 206 } 207 208 fun logOpenBroadcastDialog(uid: Int, packageName: String, instanceId: InstanceId) { 209 logger.logWithInstanceId( 210 MediaUiEvent.MEDIA_OPEN_BROADCAST_DIALOG, 211 uid, 212 packageName, 213 instanceId 214 ) 215 } 216 217 fun logSingleMediaPlayerInCarousel(uid: Int, packageName: String, instanceId: InstanceId) { 218 logger.logWithInstanceId( 219 MediaUiEvent.MEDIA_CAROUSEL_SINGLE_PLAYER, 220 uid, 221 packageName, 222 instanceId 223 ) 224 } 225 226 fun logMultipleMediaPlayersInCarousel(uid: Int, packageName: String, instanceId: InstanceId) { 227 logger.logWithInstanceId( 228 MediaUiEvent.MEDIA_CAROUSEL_MULTIPLE_PLAYERS, 229 uid, 230 packageName, 231 instanceId 232 ) 233 } 234 } 235 236 enum class MediaUiEvent(val metricId: Int) : UiEventLogger.UiEventEnum { 237 @UiEvent(doc = "A new media control was added for media playing locally on the device") 238 LOCAL_MEDIA_ADDED(1029), 239 @UiEvent(doc = "A new media control was added for media cast from the device") 240 CAST_MEDIA_ADDED(1030), 241 @UiEvent(doc = "A new media control was added for media playing remotely") 242 REMOTE_MEDIA_ADDED(1031), 243 @UiEvent(doc = "The media for an existing control was transferred to local playback") 244 TRANSFER_TO_LOCAL(1032), 245 @UiEvent(doc = "The media for an existing control was transferred to a cast device") 246 TRANSFER_TO_CAST(1033), 247 @UiEvent(doc = "The media for an existing control was transferred to a remote device") 248 TRANSFER_TO_REMOTE(1034), 249 @UiEvent(doc = "A new resumable media control was added") RESUME_MEDIA_ADDED(1013), 250 @UiEvent(doc = "An existing active media control was converted into resumable media") 251 ACTIVE_TO_RESUME(1014), 252 @UiEvent(doc = "A media control timed out") MEDIA_TIMEOUT(1015), 253 @UiEvent(doc = "A media control was removed from the carousel") MEDIA_REMOVED(1016), 254 @UiEvent(doc = "User swiped to another control within the media carousel") CAROUSEL_PAGE(1017), 255 @UiEvent(doc = "The user swiped away the media carousel") DISMISS_SWIPE(1018), 256 @UiEvent(doc = "The user long pressed on a media control") OPEN_LONG_PRESS(1019), 257 @UiEvent(doc = "The user dismissed a media control via its long press menu") 258 DISMISS_LONG_PRESS(1020), 259 @UiEvent(doc = "The user opened media settings from a media control's long press menu") 260 OPEN_SETTINGS_LONG_PRESS(1021), 261 @UiEvent(doc = "The user opened media settings from the media carousel") 262 OPEN_SETTINGS_CAROUSEL(1022), 263 @UiEvent(doc = "The play/pause button on a media control was tapped") 264 TAP_ACTION_PLAY_PAUSE(1023), 265 @UiEvent(doc = "The previous button on a media control was tapped") TAP_ACTION_PREV(1024), 266 @UiEvent(doc = "The next button on a media control was tapped") TAP_ACTION_NEXT(1025), 267 @UiEvent(doc = "A custom or generic action button on a media control was tapped") 268 TAP_ACTION_OTHER(1026), 269 @UiEvent(doc = "The user seeked on a media control using the seekbar") ACTION_SEEK(1027), 270 @UiEvent(doc = "The user opened the output switcher from a media control") 271 OPEN_OUTPUT_SWITCHER(1028), 272 @UiEvent(doc = "The user tapped on a media control view") MEDIA_TAP_CONTENT_VIEW(1036), 273 @UiEvent(doc = "The media carousel moved to QQS") MEDIA_CAROUSEL_LOCATION_QQS(1037), 274 @UiEvent(doc = "THe media carousel moved to QS") MEDIA_CAROUSEL_LOCATION_QS(1038), 275 @UiEvent(doc = "The media carousel moved to the lockscreen") 276 MEDIA_CAROUSEL_LOCATION_LOCKSCREEN(1039), 277 @UiEvent(doc = "The media carousel moved to the dream state") 278 MEDIA_CAROUSEL_LOCATION_DREAM(1040), 279 @UiEvent(doc = "A media recommendation card was added to the media carousel") 280 MEDIA_RECOMMENDATION_ADDED(1041), 281 @UiEvent(doc = "A media recommendation card was removed from the media carousel") 282 MEDIA_RECOMMENDATION_REMOVED(1042), 283 @UiEvent(doc = "An existing media control was made active as a recommendation") 284 MEDIA_RECOMMENDATION_ACTIVATED(1043), 285 @UiEvent(doc = "User tapped on an item in a media recommendation card") 286 MEDIA_RECOMMENDATION_ITEM_TAP(1044), 287 @UiEvent(doc = "User tapped on a media recommendation card") 288 MEDIA_RECOMMENDATION_CARD_TAP(1045), 289 @UiEvent(doc = "User opened the broadcast dialog from a media control") 290 MEDIA_OPEN_BROADCAST_DIALOG(1079), 291 @UiEvent(doc = "The media carousel contains one media player card") 292 MEDIA_CAROUSEL_SINGLE_PLAYER(1244), 293 @UiEvent(doc = "The media carousel contains multiple media player cards") 294 MEDIA_CAROUSEL_MULTIPLE_PLAYERS(1245); 295 296 override fun getId() = metricId 297 } 298