Skip to content

Commit 08652b6

Browse files
Robert LuoAndroid (Google) Code Review
authored andcommitted
Merge "Migrate media output switcher metrics - 1/n" into rvc-qpr-dev
2 parents 773641f + 23ccad7 commit 08652b6

9 files changed

Lines changed: 311 additions & 24 deletions

File tree

cmds/statsd/src/atoms.proto

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -442,7 +442,7 @@ message Atom {
442442
AudioPowerUsageDataReported audio_power_usage_data_reported = 275;
443443
TvTunerStateChanged tv_tuner_state_changed = 276 [(module) = "framework"];
444444
MediaOutputOpSwitchReported mediaoutput_op_switch_reported =
445-
277 [(module) = "settings"];
445+
277 [(module) = "sysui"];
446446
CellBroadcastMessageFiltered cb_message_filtered =
447447
278 [(module) = "cellbroadcast"];
448448
TvTunerDvrStatus tv_tuner_dvr_status = 279 [(module) = "framework"];
@@ -10789,7 +10789,7 @@ message BytesTransferByTagAndMetered {
1078910789
* Logs when the Media Output Switcher finishes a media switch operation.
1079010790
*
1079110791
* Logged from:
10792-
* packages/apps/Settings/src/com/android/settings/media/MediaOutputSliceWorker.java
10792+
* packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputMetricLogger.java
1079310793
*/
1079410794
message MediaOutputOpSwitchReported {
1079510795
// Source medium type before switching.

packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import androidx.annotation.VisibleForTesting;
3838
import androidx.core.graphics.drawable.IconCompat;
3939

40+
import com.android.internal.logging.UiEventLogger;
4041
import com.android.settingslib.RestrictedLockUtilsInternal;
4142
import com.android.settingslib.Utils;
4243
import com.android.settingslib.bluetooth.BluetoothUtils;
@@ -84,11 +85,14 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback {
8485
@VisibleForTesting
8586
LocalMediaManager mLocalMediaManager;
8687

88+
private MediaOutputMetricLogger mMetricLogger;
89+
private UiEventLogger mUiEventLogger;
90+
8791
@Inject
8892
public MediaOutputController(@NonNull Context context, String packageName,
8993
boolean aboveStatusbar, MediaSessionManager mediaSessionManager, LocalBluetoothManager
9094
lbm, ShadeController shadeController, ActivityStarter starter,
91-
NotificationEntryManager notificationEntryManager) {
95+
NotificationEntryManager notificationEntryManager, UiEventLogger uiEventLogger) {
9296
mContext = context;
9397
mPackageName = packageName;
9498
mMediaSessionManager = mediaSessionManager;
@@ -98,6 +102,8 @@ public MediaOutputController(@NonNull Context context, String packageName,
98102
mNotificationEntryManager = notificationEntryManager;
99103
InfoMediaManager imm = new InfoMediaManager(mContext, packageName, null, lbm);
100104
mLocalMediaManager = new LocalMediaManager(mContext, lbm, imm, packageName);
105+
mMetricLogger = new MediaOutputMetricLogger(mContext, mPackageName);
106+
mUiEventLogger = uiEventLogger;
101107
}
102108

103109
void start(@NonNull Callback cb) {
@@ -151,6 +157,7 @@ public void onDeviceListUpdate(List<MediaDevice> devices) {
151157
public void onSelectedDeviceStateChanged(MediaDevice device,
152158
@LocalMediaManager.MediaDeviceState int state) {
153159
mCallback.onRouteChanged();
160+
mMetricLogger.logOutputSuccess(device.toString(), mMediaDevices);
154161
}
155162

156163
@Override
@@ -161,6 +168,7 @@ public void onDeviceAttributesChanged() {
161168
@Override
162169
public void onRequestFailed(int reason) {
163170
mCallback.onRouteChanged();
171+
mMetricLogger.logOutputFailure(mMediaDevices, reason);
164172
}
165173

166174
CharSequence getHeaderTitle() {
@@ -311,6 +319,8 @@ void resetGroupMediaDevices() {
311319
}
312320

313321
void connectDevice(MediaDevice device) {
322+
mMetricLogger.updateOutputEndPoints(getCurrentConnectedMediaDevice(), device);
323+
314324
ThreadUtils.postOnBackgroundThread(() -> {
315325
mLocalMediaManager.connectDevice(device);
316326
});
@@ -439,7 +449,7 @@ void launchBluetoothPairing() {
439449

440450
void launchMediaOutputDialog() {
441451
mCallback.dismissDialog();
442-
new MediaOutputDialog(mContext, mAboveStatusbar, this);
452+
new MediaOutputDialog(mContext, mAboveStatusbar, this, mUiEventLogger);
443453
}
444454

445455
void launchMediaOutputGroupDialog() {

packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@
2323

2424
import androidx.core.graphics.drawable.IconCompat;
2525

26+
import com.android.internal.annotations.VisibleForTesting;
27+
import com.android.internal.logging.UiEvent;
28+
import com.android.internal.logging.UiEventLogger;
2629
import com.android.systemui.R;
2730

2831
import javax.inject.Singleton;
@@ -32,10 +35,12 @@
3235
*/
3336
@Singleton
3437
public class MediaOutputDialog extends MediaOutputBaseDialog {
38+
final UiEventLogger mUiEventLogger;
3539

3640
MediaOutputDialog(Context context, boolean aboveStatusbar, MediaOutputController
37-
mediaOutputController) {
41+
mediaOutputController, UiEventLogger uiEventLogger) {
3842
super(context, mediaOutputController);
43+
mUiEventLogger = uiEventLogger;
3944
mAdapter = new MediaOutputAdapter(mMediaOutputController);
4045
if (!aboveStatusbar) {
4146
getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
@@ -46,6 +51,7 @@ public class MediaOutputDialog extends MediaOutputBaseDialog {
4651
@Override
4752
public void onCreate(Bundle savedInstanceState) {
4853
super.onCreate(savedInstanceState);
54+
mUiEventLogger.log(MediaOutputEvent.MEDIA_OUTPUT_DIALOG_SHOW);
4955
}
5056

5157
@Override
@@ -79,4 +85,21 @@ int getStopButtonVisibility() {
7985
return mMediaOutputController.isActiveRemoteDevice(
8086
mMediaOutputController.getCurrentConnectedMediaDevice()) ? View.VISIBLE : View.GONE;
8187
}
88+
89+
@VisibleForTesting
90+
public enum MediaOutputEvent implements UiEventLogger.UiEventEnum {
91+
@UiEvent(doc = "The MediaOutput dialog became visible on the screen.")
92+
MEDIA_OUTPUT_DIALOG_SHOW(655);
93+
94+
private final int mId;
95+
96+
MediaOutputEvent(int id) {
97+
mId = id;
98+
}
99+
100+
@Override
101+
public int getId() {
102+
return mId;
103+
}
104+
}
82105
}

packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package com.android.systemui.media.dialog
1818

1919
import android.content.Context
2020
import android.media.session.MediaSessionManager
21+
import com.android.internal.logging.UiEventLogger
2122
import com.android.settingslib.bluetooth.LocalBluetoothManager
2223
import com.android.systemui.plugins.ActivityStarter
2324
import com.android.systemui.statusbar.notification.NotificationEntryManager
@@ -33,7 +34,8 @@ class MediaOutputDialogFactory @Inject constructor(
3334
private val lbm: LocalBluetoothManager?,
3435
private val shadeController: ShadeController,
3536
private val starter: ActivityStarter,
36-
private val notificationEntryManager: NotificationEntryManager
37+
private val notificationEntryManager: NotificationEntryManager,
38+
private val uiEventLogger: UiEventLogger
3739
) {
3840
companion object {
3941
var mediaOutputDialog: MediaOutputDialog? = null
@@ -43,8 +45,10 @@ class MediaOutputDialogFactory @Inject constructor(
4345
fun create(packageName: String, aboveStatusBar: Boolean) {
4446
mediaOutputDialog?.dismiss()
4547
mediaOutputDialog = MediaOutputController(context, packageName, aboveStatusBar,
46-
mediaSessionManager, lbm, shadeController, starter, notificationEntryManager).run {
47-
MediaOutputDialog(context, aboveStatusBar, this) }
48+
mediaSessionManager, lbm, shadeController, starter, notificationEntryManager,
49+
uiEventLogger).run {
50+
MediaOutputDialog(context, aboveStatusBar, this, uiEventLogger)
51+
}
4852
}
4953

5054
/** dismiss [MediaOutputDialog] if exist. */
Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
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+
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+
*/
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+
*/
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+
*/
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+
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+
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+
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+
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+
}

0 commit comments

Comments
 (0)