Add data collection and metrics for Media Output Switcher - 2/n
Fixes: 147792668
Test: ./out/host/linux-x86/bin/statsd_testdrive Atom_ID
Change-Id: I1a34228da75c197663bcfe909c961e57665590d4
diff --git a/src/com/android/settings/media/MediaDeviceUpdateWorker.java b/src/com/android/settings/media/MediaDeviceUpdateWorker.java
index bce9c34..719d2d5 100644
--- a/src/com/android/settings/media/MediaDeviceUpdateWorker.java
+++ b/src/com/android/settings/media/MediaDeviceUpdateWorker.java
@@ -51,8 +51,8 @@
public class MediaDeviceUpdateWorker extends SliceBackgroundWorker
implements LocalMediaManager.DeviceCallback {
- private final Context mContext;
- private final Collection<MediaDevice> mMediaDevices = new CopyOnWriteArrayList<>();
+ protected final Context mContext;
+ protected final Collection<MediaDevice> mMediaDevices = new CopyOnWriteArrayList<>();
private final DevicesChangedBroadcastReceiver mReceiver;
private final String mPackageName;
diff --git a/src/com/android/settings/media/MediaOutputSlice.java b/src/com/android/settings/media/MediaOutputSlice.java
index 773013e..4e54d7b 100644
--- a/src/com/android/settings/media/MediaOutputSlice.java
+++ b/src/com/android/settings/media/MediaOutputSlice.java
@@ -375,7 +375,7 @@
@Override
public Class getBackgroundWorkerClass() {
- return MediaDeviceUpdateWorker.class;
+ return MediaOutputSliceWorker.class;
}
private boolean isVisible() {
diff --git a/src/com/android/settings/media/MediaOutputSliceWorker.java b/src/com/android/settings/media/MediaOutputSliceWorker.java
new file mode 100644
index 0000000..357b234
--- /dev/null
+++ b/src/com/android/settings/media/MediaOutputSliceWorker.java
@@ -0,0 +1,211 @@
+/*
+ * 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);
+ }
+}