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 failure. 100 * @param deviceList media device list for device count updating 101 * @param reason the reason of content switching failure 102 */ logOutputFailure(List<MediaDevice> deviceList, int reason)103 public void logOutputFailure(List<MediaDevice> deviceList, int reason) { 104 if (DEBUG) { 105 Log.e(TAG, "logRequestFailed - " + reason); 106 } 107 108 updateLoggingDeviceCount(deviceList); 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__ERROR, 115 getLoggingSwitchOpSubResult(reason), 116 getLoggingPackageName(), 117 mWiredDeviceCount, 118 mConnectedBluetoothDeviceCount, 119 mRemoteDeviceCount, 120 mAppliedDeviceCountWithinRemoteGroup); 121 } 122 updateLoggingDeviceCount(List<MediaDevice> deviceList)123 private void updateLoggingDeviceCount(List<MediaDevice> deviceList) { 124 mWiredDeviceCount = mConnectedBluetoothDeviceCount = mRemoteDeviceCount = 0; 125 mAppliedDeviceCountWithinRemoteGroup = 0; 126 127 for (MediaDevice mediaDevice : deviceList) { 128 if (mediaDevice.isConnected()) { 129 switch (mediaDevice.getDeviceType()) { 130 case MediaDevice.MediaDeviceType.TYPE_3POINT5_MM_AUDIO_DEVICE: 131 case MediaDevice.MediaDeviceType.TYPE_USB_C_AUDIO_DEVICE: 132 mWiredDeviceCount++; 133 break; 134 case MediaDevice.MediaDeviceType.TYPE_BLUETOOTH_DEVICE: 135 mConnectedBluetoothDeviceCount++; 136 break; 137 case MediaDevice.MediaDeviceType.TYPE_CAST_DEVICE: 138 case MediaDevice.MediaDeviceType.TYPE_CAST_GROUP_DEVICE: 139 mRemoteDeviceCount++; 140 break; 141 default: 142 } 143 } 144 } 145 146 if (DEBUG) { 147 Log.d(TAG, "connected devices:" + " wired: " + mWiredDeviceCount 148 + " bluetooth: " + mConnectedBluetoothDeviceCount 149 + " remote: " + mRemoteDeviceCount); 150 } 151 } 152 getLoggingDeviceType(MediaDevice device, boolean isSourceDevice)153 private int getLoggingDeviceType(MediaDevice device, boolean isSourceDevice) { 154 switch (device.getDeviceType()) { 155 case MediaDevice.MediaDeviceType.TYPE_PHONE_DEVICE: 156 return isSourceDevice 157 ? SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__SOURCE__BUILTIN_SPEAKER 158 : SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__TARGET__BUILTIN_SPEAKER; 159 case MediaDevice.MediaDeviceType.TYPE_3POINT5_MM_AUDIO_DEVICE: 160 return isSourceDevice 161 ? SysUiStatsLog 162 .MEDIA_OUTPUT_OP_SWITCH_REPORTED__SOURCE__WIRED_3POINT5_MM_AUDIO 163 : SysUiStatsLog 164 .MEDIA_OUTPUT_OP_SWITCH_REPORTED__TARGET__WIRED_3POINT5_MM_AUDIO; 165 case MediaDevice.MediaDeviceType.TYPE_USB_C_AUDIO_DEVICE: 166 return isSourceDevice 167 ? SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__SOURCE__USB_C_AUDIO 168 : SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__TARGET__USB_C_AUDIO; 169 case MediaDevice.MediaDeviceType.TYPE_BLUETOOTH_DEVICE: 170 return isSourceDevice 171 ? SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__SOURCE__BLUETOOTH 172 : SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__TARGET__BLUETOOTH; 173 case MediaDevice.MediaDeviceType.TYPE_CAST_DEVICE: 174 return isSourceDevice 175 ? SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__SOURCE__REMOTE_SINGLE 176 : SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__TARGET__REMOTE_SINGLE; 177 case MediaDevice.MediaDeviceType.TYPE_CAST_GROUP_DEVICE: 178 return isSourceDevice 179 ? SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__SOURCE__REMOTE_GROUP 180 : SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__TARGET__REMOTE_GROUP; 181 default: 182 return isSourceDevice 183 ? SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__SOURCE__UNKNOWN_TYPE 184 : SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__TARGET__UNKNOWN_TYPE; 185 } 186 } 187 getLoggingSwitchOpSubResult(int reason)188 private int getLoggingSwitchOpSubResult(int reason) { 189 switch (reason) { 190 case REASON_REJECTED: 191 return SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__SUBRESULT__REJECTED; 192 case REASON_NETWORK_ERROR: 193 return SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__SUBRESULT__NETWORK_ERROR; 194 case REASON_ROUTE_NOT_AVAILABLE: 195 return SysUiStatsLog 196 .MEDIA_OUTPUT_OP_SWITCH_REPORTED__SUBRESULT__ROUTE_NOT_AVAILABLE; 197 case REASON_INVALID_COMMAND: 198 return SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__SUBRESULT__INVALID_COMMAND; 199 case REASON_UNKNOWN_ERROR: 200 default: 201 return SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__SUBRESULT__UNKNOWN_ERROR; 202 } 203 } 204 getLoggingPackageName()205 private String getLoggingPackageName() { 206 if (mPackageName != null && !mPackageName.isEmpty()) { 207 try { 208 final ApplicationInfo applicationInfo = mContext.getPackageManager() 209 .getApplicationInfo(mPackageName, /* default flag */ 0); 210 if ((applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0 211 || (applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) { 212 return mPackageName; 213 } 214 } catch (Exception ex) { 215 Log.e(TAG, mPackageName + " is invalid."); 216 } 217 } 218 219 return ""; 220 } 221 } 222