| /* |
| * Copyright (C) 2020 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.settings.media; |
| |
| import static android.media.MediaRoute2ProviderService.REASON_INVALID_COMMAND; |
| import static android.media.MediaRoute2ProviderService.REASON_NETWORK_ERROR; |
| import static android.media.MediaRoute2ProviderService.REASON_REJECTED; |
| import static android.media.MediaRoute2ProviderService.REASON_ROUTE_NOT_AVAILABLE; |
| import static android.media.MediaRoute2ProviderService.REASON_UNKNOWN_ERROR; |
| |
| import android.content.Context; |
| import android.content.pm.ApplicationInfo; |
| import android.net.Uri; |
| import android.util.Log; |
| |
| import com.android.settings.core.instrumentation.SettingsStatsLog; |
| import com.android.settingslib.media.MediaDevice; |
| |
| /** |
| * SliceBackgroundWorker for the MediaOutputSlice class. |
| * It inherits from MediaDeviceUpdateWorker and add metrics logging. |
| */ |
| public class MediaOutputSliceWorker extends MediaDeviceUpdateWorker { |
| |
| private static final String TAG = "MediaOutputSliceWorker"; |
| private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG); |
| |
| private MediaDevice mSourceDevice, mTargetDevice; |
| private int mWiredDeviceCount; |
| private int mConnectedBluetoothDeviceCount; |
| private int mRemoteDeviceCount; |
| private int mAppliedDeviceCountWithinRemoteGroup; |
| |
| public MediaOutputSliceWorker(Context context, Uri uri) { |
| super(context, uri); |
| } |
| |
| @Override |
| public void connectDevice(MediaDevice device) { |
| mSourceDevice = mLocalMediaManager.getCurrentConnectedDevice(); |
| mTargetDevice = device; |
| |
| if (DBG) { |
| Log.d(TAG, "connectDevice -" |
| + " source:" + mSourceDevice.toString() |
| + " target:" + mTargetDevice.toString()); |
| } |
| |
| super.connectDevice(device); |
| } |
| |
| private int getLoggingDeviceType(MediaDevice device, boolean isSourceDevice) { |
| switch (device.getDeviceType()) { |
| case MediaDevice.MediaDeviceType.TYPE_PHONE_DEVICE: |
| return isSourceDevice |
| ? SettingsStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__SOURCE__BUILTIN_SPEAKER |
| : SettingsStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__TARGET__BUILTIN_SPEAKER; |
| case MediaDevice.MediaDeviceType.TYPE_3POINT5_MM_AUDIO_DEVICE: |
| return isSourceDevice |
| ? SettingsStatsLog |
| .MEDIA_OUTPUT_OP_SWITCH_REPORTED__SOURCE__WIRED_3POINT5_MM_AUDIO |
| : SettingsStatsLog |
| .MEDIA_OUTPUT_OP_SWITCH_REPORTED__TARGET__WIRED_3POINT5_MM_AUDIO; |
| case MediaDevice.MediaDeviceType.TYPE_USB_C_AUDIO_DEVICE: |
| return isSourceDevice |
| ? SettingsStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__SOURCE__USB_C_AUDIO |
| : SettingsStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__TARGET__USB_C_AUDIO; |
| case MediaDevice.MediaDeviceType.TYPE_BLUETOOTH_DEVICE: |
| return isSourceDevice |
| ? SettingsStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__SOURCE__BLUETOOTH |
| : SettingsStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__TARGET__BLUETOOTH; |
| case MediaDevice.MediaDeviceType.TYPE_CAST_DEVICE: |
| return isSourceDevice |
| ? SettingsStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__SOURCE__REMOTE_SINGLE |
| : SettingsStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__TARGET__REMOTE_SINGLE; |
| case MediaDevice.MediaDeviceType.TYPE_CAST_GROUP_DEVICE: |
| return isSourceDevice |
| ? SettingsStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__SOURCE__REMOTE_GROUP |
| : SettingsStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__TARGET__REMOTE_GROUP; |
| default: |
| return isSourceDevice |
| ? SettingsStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__SOURCE__UNKNOWN_TYPE |
| : SettingsStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__TARGET__UNKNOWN_TYPE; |
| } |
| } |
| |
| private int getLoggingSwitchOpSubResult(int reason) { |
| switch (reason) { |
| case REASON_REJECTED: |
| return SettingsStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__SUBRESULT__REJECTED; |
| case REASON_NETWORK_ERROR: |
| return SettingsStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__SUBRESULT__NETWORK_ERROR; |
| case REASON_ROUTE_NOT_AVAILABLE: |
| return SettingsStatsLog |
| .MEDIA_OUTPUT_OP_SWITCH_REPORTED__SUBRESULT__ROUTE_NOT_AVAILABLE; |
| case REASON_INVALID_COMMAND: |
| return SettingsStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__SUBRESULT__INVALID_COMMAND; |
| case REASON_UNKNOWN_ERROR: |
| default: |
| return SettingsStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__SUBRESULT__UNKNOWN_ERROR; |
| } |
| } |
| |
| private String getLoggingPackageName() { |
| final String packageName = getPackageName(); |
| if (packageName != null && !packageName.isEmpty()) { |
| try { |
| final ApplicationInfo applicationInfo = mContext.getPackageManager() |
| .getApplicationInfo(packageName, /* default flag */ 0); |
| if ((applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0 |
| || (applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) { |
| return packageName; |
| } |
| } catch (Exception ex) { |
| Log.e(TAG, packageName + "is invalid."); |
| } |
| } |
| |
| return ""; |
| } |
| |
| private void updateLoggingDeviceCount() { |
| mWiredDeviceCount = mConnectedBluetoothDeviceCount = mRemoteDeviceCount = 0; |
| mAppliedDeviceCountWithinRemoteGroup = 0; |
| |
| for (MediaDevice mediaDevice : mMediaDevices) { |
| if (mediaDevice.isConnected()) { |
| switch (mediaDevice.getDeviceType()) { |
| case MediaDevice.MediaDeviceType.TYPE_3POINT5_MM_AUDIO_DEVICE: |
| case MediaDevice.MediaDeviceType.TYPE_USB_C_AUDIO_DEVICE: |
| mWiredDeviceCount++; |
| break; |
| case MediaDevice.MediaDeviceType.TYPE_BLUETOOTH_DEVICE: |
| mConnectedBluetoothDeviceCount++; |
| break; |
| case MediaDevice.MediaDeviceType.TYPE_CAST_DEVICE: |
| case MediaDevice.MediaDeviceType.TYPE_CAST_GROUP_DEVICE: |
| mRemoteDeviceCount++; |
| break; |
| default: |
| } |
| } |
| } |
| |
| if (DBG) { |
| Log.d(TAG, "connected devices:" + " wired: " + mWiredDeviceCount |
| + " bluetooth: " + mConnectedBluetoothDeviceCount |
| + " remote: " + mRemoteDeviceCount); |
| } |
| } |
| |
| @Override |
| public void onSelectedDeviceStateChanged(MediaDevice device, int state) { |
| if (DBG) { |
| Log.d(TAG, "onSelectedDeviceStateChanged - " + device.toString()); |
| } |
| |
| updateLoggingDeviceCount(); |
| |
| SettingsStatsLog.write( |
| SettingsStatsLog.MEDIAOUTPUT_OP_SWITCH_REPORTED, |
| getLoggingDeviceType(mSourceDevice, true), |
| getLoggingDeviceType(mTargetDevice, false), |
| SettingsStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__RESULT__OK, |
| SettingsStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__SUBRESULT__NO_ERROR, |
| getLoggingPackageName(), |
| mWiredDeviceCount, |
| mConnectedBluetoothDeviceCount, |
| mRemoteDeviceCount, |
| mAppliedDeviceCountWithinRemoteGroup); |
| |
| super.onSelectedDeviceStateChanged(device, state); |
| } |
| |
| @Override |
| public void onRequestFailed(int reason) { |
| if (DBG) { |
| Log.e(TAG, "onRequestFailed - " + reason); |
| } |
| |
| updateLoggingDeviceCount(); |
| |
| SettingsStatsLog.write( |
| SettingsStatsLog.MEDIAOUTPUT_OP_SWITCH_REPORTED, |
| getLoggingDeviceType(mSourceDevice, true), |
| getLoggingDeviceType(mTargetDevice, false), |
| SettingsStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__RESULT__ERROR, |
| getLoggingSwitchOpSubResult(reason), |
| getLoggingPackageName(), |
| mWiredDeviceCount, |
| mConnectedBluetoothDeviceCount, |
| mRemoteDeviceCount, |
| mAppliedDeviceCountWithinRemoteGroup); |
| |
| super.onRequestFailed(reason); |
| } |
| } |