• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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.dialog;
18 
19 import static android.media.MediaRoute2ProviderService.REASON_INVALID_COMMAND;
20 import static android.media.MediaRoute2ProviderService.REASON_NETWORK_ERROR;
21 import static android.media.MediaRoute2ProviderService.REASON_REJECTED;
22 import static android.media.MediaRoute2ProviderService.REASON_ROUTE_NOT_AVAILABLE;
23 import static android.media.MediaRoute2ProviderService.REASON_UNKNOWN_ERROR;
24 
25 import android.content.Context;
26 import android.content.pm.ApplicationInfo;
27 import android.util.Log;
28 
29 import com.android.settingslib.media.MediaDevice;
30 import com.android.systemui.shared.system.SysUiStatsLog;
31 
32 import java.util.List;
33 
34 /**
35  * Metric logger for media output features
36  */
37 public class MediaOutputMetricLogger {
38 
39     private static final String TAG = "MediaOutputMetricLogger";
40     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
41 
42     private final Context mContext;
43     private final String mPackageName;
44     private MediaDevice mSourceDevice, mTargetDevice;
45     private int mWiredDeviceCount;
46     private int mConnectedBluetoothDeviceCount;
47     private int mRemoteDeviceCount;
48     private int mAppliedDeviceCountWithinRemoteGroup;
49 
MediaOutputMetricLogger(Context context, String packageName)50     public MediaOutputMetricLogger(Context context, String packageName) {
51         mContext = context;
52         mPackageName = packageName;
53     }
54 
55     /**
56      * Update the endpoints of a content switching operation.
57      * This method should be called before a switching operation, so the metric logger can track
58      * source and target devices.
59      * @param source the current connected media device
60      * @param target the target media device for content switching to
61      */
updateOutputEndPoints(MediaDevice source, MediaDevice target)62     public void updateOutputEndPoints(MediaDevice source, MediaDevice target) {
63         mSourceDevice = source;
64         mTargetDevice = target;
65 
66         if (DEBUG) {
67             Log.d(TAG, "updateOutputEndPoints -"
68                     + " source:" + mSourceDevice.toString()
69                     + " target:" + mTargetDevice.toString());
70         }
71     }
72 
73     /**
74      * Do the metric logging of content switching success.
75      * @param selectedDeviceType string representation of the target media device
76      * @param deviceList media device list for device count updating
77      */
logOutputSuccess(String selectedDeviceType, List<MediaDevice> deviceList)78     public void logOutputSuccess(String selectedDeviceType, List<MediaDevice> deviceList) {
79         if (DEBUG) {
80             Log.d(TAG, "logOutputSuccess - selected device: " + selectedDeviceType);
81         }
82 
83         updateLoggingDeviceCount(deviceList);
84 
85         SysUiStatsLog.write(
86                 SysUiStatsLog.MEDIAOUTPUT_OP_SWITCH_REPORTED,
87                 getLoggingDeviceType(mSourceDevice, true),
88                 getLoggingDeviceType(mTargetDevice, false),
89                 SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__RESULT__OK,
90                 SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__SUBRESULT__NO_ERROR,
91                 getLoggingPackageName(),
92                 mWiredDeviceCount,
93                 mConnectedBluetoothDeviceCount,
94                 mRemoteDeviceCount,
95                 mAppliedDeviceCountWithinRemoteGroup);
96     }
97 
98     /**
99      * Do the metric logging of content switching success.
100      * @param selectedDeviceType string representation of the target media device
101      * @param deviceItemList media item list for device count updating
102      */
logOutputItemSuccess(String selectedDeviceType, List<MediaItem> deviceItemList)103     public void logOutputItemSuccess(String selectedDeviceType, List<MediaItem> deviceItemList) {
104         if (DEBUG) {
105             Log.d(TAG, "logOutputSuccess - selected device: " + selectedDeviceType);
106         }
107 
108         updateLoggingMediaItemCount(deviceItemList);
109 
110         SysUiStatsLog.write(
111                 SysUiStatsLog.MEDIAOUTPUT_OP_SWITCH_REPORTED,
112                 getLoggingDeviceType(mSourceDevice, true),
113                 getLoggingDeviceType(mTargetDevice, false),
114                 SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__RESULT__OK,
115                 SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__SUBRESULT__NO_ERROR,
116                 getLoggingPackageName(),
117                 mWiredDeviceCount,
118                 mConnectedBluetoothDeviceCount,
119                 mRemoteDeviceCount,
120                 mAppliedDeviceCountWithinRemoteGroup);
121     }
122 
123     /**
124      * Do the metric logging of volume adjustment.
125      * @param source the device been adjusted
126      */
logInteractionAdjustVolume(MediaDevice source)127     public void logInteractionAdjustVolume(MediaDevice source) {
128         if (DEBUG) {
129             Log.d(TAG, "logInteraction - AdjustVolume");
130         }
131 
132         SysUiStatsLog.write(
133                 SysUiStatsLog.MEDIAOUTPUT_OP_INTERACTION_REPORT,
134                 SysUiStatsLog.MEDIA_OUTPUT_OP_INTERACTION_REPORTED__INTERACTION_TYPE__ADJUST_VOLUME,
135                 getInteractionDeviceType(source),
136                 getLoggingPackageName());
137     }
138 
139     /**
140      * Do the metric logging of stop casting.
141      */
logInteractionStopCasting()142     public void logInteractionStopCasting() {
143         if (DEBUG) {
144             Log.d(TAG, "logInteraction - Stop casting");
145         }
146 
147         SysUiStatsLog.write(
148                 SysUiStatsLog.MEDIAOUTPUT_OP_INTERACTION_REPORT,
149                 SysUiStatsLog.MEDIA_OUTPUT_OP_INTERACTION_REPORTED__INTERACTION_TYPE__STOP_CASTING,
150                 SysUiStatsLog.MEDIA_OUTPUT_OP_INTERACTION_REPORTED__TARGET__UNKNOWN_TYPE,
151                 getLoggingPackageName());
152     }
153 
154     /**
155      * Do the metric logging of device expansion.
156      */
logInteractionExpansion(MediaDevice source)157     public void logInteractionExpansion(MediaDevice source) {
158         if (DEBUG) {
159             Log.d(TAG, "logInteraction - Expansion");
160         }
161 
162         SysUiStatsLog.write(
163                 SysUiStatsLog.MEDIAOUTPUT_OP_INTERACTION_REPORT,
164                 SysUiStatsLog.MEDIA_OUTPUT_OP_INTERACTION_REPORTED__INTERACTION_TYPE__EXPANSION,
165                 getInteractionDeviceType(source),
166                 getLoggingPackageName());
167     }
168 
169     /**
170      * Do the metric logging of content switching failure.
171      * @param deviceList media device list for device count updating
172      * @param reason the reason of content switching failure
173      */
logOutputFailure(List<MediaDevice> deviceList, int reason)174     public void logOutputFailure(List<MediaDevice> deviceList, int reason) {
175         if (DEBUG) {
176             Log.e(TAG, "logRequestFailed - " + reason);
177         }
178 
179         updateLoggingDeviceCount(deviceList);
180 
181         SysUiStatsLog.write(
182                 SysUiStatsLog.MEDIAOUTPUT_OP_SWITCH_REPORTED,
183                 getLoggingDeviceType(mSourceDevice, true),
184                 getLoggingDeviceType(mTargetDevice, false),
185                 SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__RESULT__ERROR,
186                 getLoggingSwitchOpSubResult(reason),
187                 getLoggingPackageName(),
188                 mWiredDeviceCount,
189                 mConnectedBluetoothDeviceCount,
190                 mRemoteDeviceCount,
191                 mAppliedDeviceCountWithinRemoteGroup);
192     }
193 
194     /**
195      * Do the metric logging of content switching failure.
196      * @param deviceItemList media item list for device count updating
197      * @param reason the reason of content switching failure
198      */
logOutputItemFailure(List<MediaItem> deviceItemList, int reason)199     public void logOutputItemFailure(List<MediaItem> deviceItemList, int reason) {
200         if (DEBUG) {
201             Log.e(TAG, "logRequestFailed - " + reason);
202         }
203 
204         updateLoggingMediaItemCount(deviceItemList);
205 
206         SysUiStatsLog.write(
207                 SysUiStatsLog.MEDIAOUTPUT_OP_SWITCH_REPORTED,
208                 getLoggingDeviceType(mSourceDevice, true),
209                 getLoggingDeviceType(mTargetDevice, false),
210                 SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__RESULT__ERROR,
211                 getLoggingSwitchOpSubResult(reason),
212                 getLoggingPackageName(),
213                 mWiredDeviceCount,
214                 mConnectedBluetoothDeviceCount,
215                 mRemoteDeviceCount,
216                 mAppliedDeviceCountWithinRemoteGroup);
217     }
218 
updateLoggingDeviceCount(List<MediaDevice> deviceList)219     private void updateLoggingDeviceCount(List<MediaDevice> deviceList) {
220         mWiredDeviceCount = mConnectedBluetoothDeviceCount = mRemoteDeviceCount = 0;
221         mAppliedDeviceCountWithinRemoteGroup = 0;
222 
223         for (MediaDevice mediaDevice : deviceList) {
224             if (mediaDevice.isConnected()) {
225                 switch (mediaDevice.getDeviceType()) {
226                     case MediaDevice.MediaDeviceType.TYPE_3POINT5_MM_AUDIO_DEVICE:
227                     case MediaDevice.MediaDeviceType.TYPE_USB_C_AUDIO_DEVICE:
228                         mWiredDeviceCount++;
229                         break;
230                     case MediaDevice.MediaDeviceType.TYPE_BLUETOOTH_DEVICE:
231                         mConnectedBluetoothDeviceCount++;
232                         break;
233                     case MediaDevice.MediaDeviceType.TYPE_CAST_DEVICE:
234                     case MediaDevice.MediaDeviceType.TYPE_CAST_GROUP_DEVICE:
235                         mRemoteDeviceCount++;
236                         break;
237                     default:
238                 }
239             }
240         }
241 
242         if (DEBUG) {
243             Log.d(TAG, "connected devices:" + " wired: " + mWiredDeviceCount
244                     + " bluetooth: " + mConnectedBluetoothDeviceCount
245                     + " remote: " + mRemoteDeviceCount);
246         }
247     }
248 
updateLoggingMediaItemCount(List<MediaItem> deviceItemList)249     private void updateLoggingMediaItemCount(List<MediaItem> deviceItemList) {
250         mWiredDeviceCount = mConnectedBluetoothDeviceCount = mRemoteDeviceCount = 0;
251         mAppliedDeviceCountWithinRemoteGroup = 0;
252 
253         for (MediaItem mediaItem: deviceItemList) {
254             if (mediaItem.getMediaDevice().isPresent()
255                     && mediaItem.getMediaDevice().get().isConnected()) {
256                 switch (mediaItem.getMediaDevice().get().getDeviceType()) {
257                     case MediaDevice.MediaDeviceType.TYPE_3POINT5_MM_AUDIO_DEVICE:
258                     case MediaDevice.MediaDeviceType.TYPE_USB_C_AUDIO_DEVICE:
259                         mWiredDeviceCount++;
260                         break;
261                     case MediaDevice.MediaDeviceType.TYPE_BLUETOOTH_DEVICE:
262                         mConnectedBluetoothDeviceCount++;
263                         break;
264                     case MediaDevice.MediaDeviceType.TYPE_CAST_DEVICE:
265                     case MediaDevice.MediaDeviceType.TYPE_CAST_GROUP_DEVICE:
266                         mRemoteDeviceCount++;
267                         break;
268                     default:
269                 }
270             }
271         }
272 
273         if (DEBUG) {
274             Log.d(TAG, "connected devices:" + " wired: " + mWiredDeviceCount
275                     + " bluetooth: " + mConnectedBluetoothDeviceCount
276                     + " remote: " + mRemoteDeviceCount);
277         }
278     }
279 
getLoggingDeviceType(MediaDevice device, boolean isSourceDevice)280     private int getLoggingDeviceType(MediaDevice device, boolean isSourceDevice) {
281         if (device == null) {
282             return isSourceDevice
283                     ? SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__SOURCE__UNKNOWN_TYPE
284                     : SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__TARGET__UNKNOWN_TYPE;
285         }
286         switch (device.getDeviceType()) {
287             case MediaDevice.MediaDeviceType.TYPE_PHONE_DEVICE:
288                 return isSourceDevice
289                         ? SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__SOURCE__BUILTIN_SPEAKER
290                         : SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__TARGET__BUILTIN_SPEAKER;
291             case MediaDevice.MediaDeviceType.TYPE_3POINT5_MM_AUDIO_DEVICE:
292                 return isSourceDevice
293                         ? SysUiStatsLog
294                         .MEDIA_OUTPUT_OP_SWITCH_REPORTED__SOURCE__WIRED_3POINT5_MM_AUDIO
295                         : SysUiStatsLog
296                                 .MEDIA_OUTPUT_OP_SWITCH_REPORTED__TARGET__WIRED_3POINT5_MM_AUDIO;
297             case MediaDevice.MediaDeviceType.TYPE_USB_C_AUDIO_DEVICE:
298                 return isSourceDevice
299                         ? SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__SOURCE__USB_C_AUDIO
300                         : SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__TARGET__USB_C_AUDIO;
301             case MediaDevice.MediaDeviceType.TYPE_BLUETOOTH_DEVICE:
302                 return isSourceDevice
303                         ? SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__SOURCE__BLUETOOTH
304                         : SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__TARGET__BLUETOOTH;
305             case MediaDevice.MediaDeviceType.TYPE_CAST_DEVICE:
306                 return isSourceDevice
307                         ? SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__SOURCE__REMOTE_SINGLE
308                         : SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__TARGET__REMOTE_SINGLE;
309             case MediaDevice.MediaDeviceType.TYPE_CAST_GROUP_DEVICE:
310                 return isSourceDevice
311                         ? SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__SOURCE__REMOTE_GROUP
312                         : SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__TARGET__REMOTE_GROUP;
313             default:
314                 return isSourceDevice
315                         ? SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__SOURCE__UNKNOWN_TYPE
316                         : SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__TARGET__UNKNOWN_TYPE;
317         }
318     }
319 
getInteractionDeviceType(MediaDevice device)320     private int getInteractionDeviceType(MediaDevice device) {
321         if (device == null) {
322             return SysUiStatsLog.MEDIA_OUTPUT_OP_INTERACTION_REPORTED__TARGET__UNKNOWN_TYPE;
323         }
324         switch (device.getDeviceType()) {
325             case MediaDevice.MediaDeviceType.TYPE_PHONE_DEVICE:
326                 return SysUiStatsLog.MEDIA_OUTPUT_OP_INTERACTION_REPORTED__TARGET__BUILTIN_SPEAKER;
327             case MediaDevice.MediaDeviceType.TYPE_3POINT5_MM_AUDIO_DEVICE:
328                 return SysUiStatsLog
329                         .MEDIA_OUTPUT_OP_INTERACTION_REPORTED__TARGET__WIRED_3POINT5_MM_AUDIO;
330             case MediaDevice.MediaDeviceType.TYPE_USB_C_AUDIO_DEVICE:
331                 return SysUiStatsLog.MEDIA_OUTPUT_OP_INTERACTION_REPORTED__TARGET__USB_C_AUDIO;
332             case MediaDevice.MediaDeviceType.TYPE_BLUETOOTH_DEVICE:
333                 return SysUiStatsLog.MEDIA_OUTPUT_OP_INTERACTION_REPORTED__TARGET__BLUETOOTH;
334             case MediaDevice.MediaDeviceType.TYPE_CAST_DEVICE:
335                 return SysUiStatsLog.MEDIA_OUTPUT_OP_INTERACTION_REPORTED__TARGET__REMOTE_SINGLE;
336             case MediaDevice.MediaDeviceType.TYPE_CAST_GROUP_DEVICE:
337                 return SysUiStatsLog.MEDIA_OUTPUT_OP_INTERACTION_REPORTED__TARGET__REMOTE_GROUP;
338             default:
339                 return SysUiStatsLog.MEDIA_OUTPUT_OP_INTERACTION_REPORTED__TARGET__UNKNOWN_TYPE;
340         }
341     }
342 
343 
getLoggingSwitchOpSubResult(int reason)344     private int getLoggingSwitchOpSubResult(int reason) {
345         switch (reason) {
346             case REASON_REJECTED:
347                 return SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__SUBRESULT__REJECTED;
348             case REASON_NETWORK_ERROR:
349                 return SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__SUBRESULT__NETWORK_ERROR;
350             case REASON_ROUTE_NOT_AVAILABLE:
351                 return SysUiStatsLog
352                         .MEDIA_OUTPUT_OP_SWITCH_REPORTED__SUBRESULT__ROUTE_NOT_AVAILABLE;
353             case REASON_INVALID_COMMAND:
354                 return SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__SUBRESULT__INVALID_COMMAND;
355             case REASON_UNKNOWN_ERROR:
356             default:
357                 return SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__SUBRESULT__UNKNOWN_ERROR;
358         }
359     }
360 
getLoggingPackageName()361     private String getLoggingPackageName() {
362         if (mPackageName != null && !mPackageName.isEmpty()) {
363             try {
364                 final ApplicationInfo applicationInfo = mContext.getPackageManager()
365                         .getApplicationInfo(mPackageName, /* default flag */ 0);
366                 if ((applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0
367                         || (applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
368                     return mPackageName;
369                 }
370             } catch (Exception ex) {
371                 Log.e(TAG, mPackageName + " is invalid.");
372             }
373         }
374 
375         return "";
376     }
377 }
378