1 /*
2  * Copyright (C) 2017 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.server.audio;
18 
19 import android.annotation.NonNull;
20 import android.media.AudioDeviceAttributes;
21 import android.media.AudioManager;
22 import android.media.AudioSystem;
23 import android.media.MediaMetrics;
24 
25 import com.android.server.audio.AudioDeviceInventory.WiredDeviceConnectionState;
26 import com.android.server.utils.EventLogger;
27 
28 
29 public class AudioServiceEvents {
30 
31     final static class PhoneStateEvent extends EventLogger.Event {
32         static final int MODE_SET = 0;
33         static final int MODE_IN_COMMUNICATION_TIMEOUT = 1;
34 
35         final int mOp;
36         final String mPackage;
37         final int mOwnerPid;
38         final int mRequesterPid;
39         final int mRequestedMode;
40         final int mActualMode;
41 
42         /** used for MODE_SET */
PhoneStateEvent(String callingPackage, int requesterPid, int requestedMode, int ownerPid, int actualMode)43         PhoneStateEvent(String callingPackage, int requesterPid, int requestedMode,
44                         int ownerPid, int actualMode) {
45             mOp = MODE_SET;
46             mPackage = callingPackage;
47             mRequesterPid = requesterPid;
48             mRequestedMode = requestedMode;
49             mOwnerPid = ownerPid;
50             mActualMode = actualMode;
51             logMetricEvent();
52         }
53 
54         /** used for MODE_IN_COMMUNICATION_TIMEOUT */
PhoneStateEvent(String callingPackage, int ownerPid)55         PhoneStateEvent(String callingPackage, int ownerPid) {
56             mOp = MODE_IN_COMMUNICATION_TIMEOUT;
57             mPackage = callingPackage;
58             mOwnerPid = ownerPid;
59             mRequesterPid = 0;
60             mRequestedMode = 0;
61             mActualMode = 0;
62             logMetricEvent();
63         }
64 
65         @Override
eventToString()66         public String eventToString() {
67             switch (mOp) {
68                 case MODE_SET:
69                     return new StringBuilder("setMode(")
70                             .append(AudioSystem.modeToString(mRequestedMode))
71                             .append(") from package=").append(mPackage)
72                             .append(" pid=").append(mRequesterPid)
73                             .append(" selected mode=")
74                             .append(AudioSystem.modeToString(mActualMode))
75                             .append(" by pid=").append(mOwnerPid).toString();
76                 case MODE_IN_COMMUNICATION_TIMEOUT:
77                     return new StringBuilder("mode IN COMMUNICATION timeout")
78                             .append(" for package=").append(mPackage)
79                             .append(" pid=").append(mOwnerPid).toString();
80                 default: return new StringBuilder("FIXME invalid op:").append(mOp).toString();
81             }
82         }
83 
84         /**
85          * Audio Analytics unique Id.
86          */
87         private static final String mMetricsId = MediaMetrics.Name.AUDIO_MODE;
88 
logMetricEvent()89         private void logMetricEvent() {
90             switch (mOp) {
91                 case MODE_SET:
92                     new MediaMetrics.Item(mMetricsId)
93                             .set(MediaMetrics.Property.EVENT, "set")
94                             .set(MediaMetrics.Property.REQUESTED_MODE,
95                                     AudioSystem.modeToString(mRequestedMode))
96                             .set(MediaMetrics.Property.MODE, AudioSystem.modeToString(mActualMode))
97                             .set(MediaMetrics.Property.CALLING_PACKAGE, mPackage)
98                             .record();
99                     return;
100                 case MODE_IN_COMMUNICATION_TIMEOUT:
101                     new MediaMetrics.Item(mMetricsId)
102                             .set(MediaMetrics.Property.EVENT, "inCommunicationTimeout")
103                             .set(MediaMetrics.Property.CALLING_PACKAGE, mPackage)
104                             .record();
105                     return;
106                 default: return;
107             }
108         }
109     }
110 
111     final static class WiredDevConnectEvent extends EventLogger.Event {
112         final WiredDeviceConnectionState mState;
113 
WiredDevConnectEvent(WiredDeviceConnectionState state)114         WiredDevConnectEvent(WiredDeviceConnectionState state) {
115             mState = state;
116         }
117 
118         @Override
eventToString()119         public String eventToString() {
120             return new StringBuilder("setWiredDeviceConnectionState(")
121                     .append(" type:").append(
122                             Integer.toHexString(mState.mAttributes.getInternalType()))
123                     .append(" state:").append(AudioSystem.deviceStateToString(mState.mState))
124                     .append(" addr:").append(mState.mAttributes.getAddress())
125                     .append(" name:").append(mState.mAttributes.getName())
126                     .append(") from ").append(mState.mCaller).toString();
127         }
128     }
129 
130     final static class ForceUseEvent extends EventLogger.Event {
131         final int mUsage;
132         final int mConfig;
133         final String mReason;
134 
ForceUseEvent(int usage, int config, String reason)135         ForceUseEvent(int usage, int config, String reason) {
136             mUsage = usage;
137             mConfig = config;
138             mReason = reason;
139         }
140 
141         @Override
eventToString()142         public String eventToString() {
143             return new StringBuilder("setForceUse(")
144                     .append(AudioSystem.forceUseUsageToString(mUsage))
145                     .append(", ").append(AudioSystem.forceUseConfigToString(mConfig))
146                     .append(") due to ").append(mReason).toString();
147         }
148     }
149 
150     static final class VolChangedBroadcastEvent extends EventLogger.Event {
151         final int mStreamType;
152         final int mAliasStreamType;
153         final int mIndex;
154 
VolChangedBroadcastEvent(int stream, int alias, int index)155         VolChangedBroadcastEvent(int stream, int alias, int index) {
156             mStreamType = stream;
157             mAliasStreamType = alias;
158             mIndex = index;
159         }
160 
161         @Override
eventToString()162         public String eventToString() {
163             return new StringBuilder("sending VOLUME_CHANGED stream:")
164                     .append(AudioSystem.streamToString(mStreamType))
165                     .append(" index:").append(mIndex)
166                     .append(" alias:").append(AudioSystem.streamToString(mAliasStreamType))
167                     .toString();
168         }
169     }
170 
171     static final class DeviceVolumeEvent extends EventLogger.Event {
172         final int mStream;
173         final int mVolIndex;
174         final String mDeviceNativeType;
175         final String mDeviceAddress;
176         final String mCaller;
177         final int mDeviceForStream;
178         final boolean mSkipped;
179 
DeviceVolumeEvent(int streamType, int index, @NonNull AudioDeviceAttributes device, int deviceForStream, String callingPackage, boolean skipped)180         DeviceVolumeEvent(int streamType, int index, @NonNull AudioDeviceAttributes device,
181                 int deviceForStream, String callingPackage, boolean skipped) {
182             mStream = streamType;
183             mVolIndex = index;
184             mDeviceNativeType = "0x" + Integer.toHexString(device.getInternalType());
185             mDeviceAddress = device.getAddress();
186             mDeviceForStream = deviceForStream;
187             mCaller = callingPackage;
188             mSkipped = skipped;
189             // log metrics
190             new MediaMetrics.Item(MediaMetrics.Name.AUDIO_VOLUME_EVENT)
191                     .set(MediaMetrics.Property.EVENT, "setDeviceVolume")
192                     .set(MediaMetrics.Property.STREAM_TYPE,
193                             AudioSystem.streamToString(mStream))
194                     .set(MediaMetrics.Property.INDEX, mVolIndex)
195                     .set(MediaMetrics.Property.DEVICE, mDeviceNativeType)
196                     .set(MediaMetrics.Property.ADDRESS, mDeviceAddress)
197                     .set(MediaMetrics.Property.CALLING_PACKAGE, mCaller)
198                     .record();
199         }
200 
201         @Override
eventToString()202         public String eventToString() {
203             final StringBuilder sb = new StringBuilder("setDeviceVolume(stream:")
204                     .append(AudioSystem.streamToString(mStream))
205                     .append(" index:").append(mVolIndex)
206                     .append(" device:").append(mDeviceNativeType)
207                     .append(" addr:").append(mDeviceAddress)
208                     .append(") from ").append(mCaller);
209             if (mSkipped) {
210                 sb.append(" skipped [device in use]");
211             } else {
212                 sb.append(" currDevForStream:Ox").append(Integer.toHexString(mDeviceForStream));
213             }
214             return sb.toString();
215         }
216     }
217 
218     final static class VolumeEvent extends EventLogger.Event {
219         static final int VOL_ADJUST_SUGG_VOL = 0;
220         static final int VOL_ADJUST_STREAM_VOL = 1;
221         static final int VOL_SET_STREAM_VOL = 2;
222         static final int VOL_SET_HEARING_AID_VOL = 3;
223         static final int VOL_SET_AVRCP_VOL = 4;
224         static final int VOL_ADJUST_VOL_UID = 5;
225         static final int VOL_VOICE_ACTIVITY_HEARING_AID = 6;
226         static final int VOL_MODE_CHANGE_HEARING_AID = 7;
227         static final int VOL_SET_GROUP_VOL = 8;
228         static final int VOL_MUTE_STREAM_INT = 9;
229         static final int VOL_SET_LE_AUDIO_VOL = 10;
230         static final int VOL_ADJUST_GROUP_VOL = 11;
231 
232         final int mOp;
233         final int mStream;
234         final int mVal1;
235         final int mVal2;
236         final String mCaller;
237         final String mGroupName;
238 
239         /** used for VOL_ADJUST_VOL_UID,
240          *           VOL_ADJUST_SUGG_VOL,
241          *           VOL_ADJUST_STREAM_VOL,
242          *           VOL_SET_STREAM_VOL */
VolumeEvent(int op, int stream, int val1, int val2, String caller)243         VolumeEvent(int op, int stream, int val1, int val2, String caller) {
244             mOp = op;
245             mStream = stream;
246             mVal1 = val1;
247             mVal2 = val2;
248             mCaller = caller;
249             mGroupName = null;
250             logMetricEvent();
251         }
252 
253         /** used for VOL_SET_HEARING_AID_VOL*/
VolumeEvent(int op, int index, int gainDb)254         VolumeEvent(int op, int index, int gainDb) {
255             mOp = op;
256             mVal1 = index;
257             mVal2 = gainDb;
258             // unused
259             mStream = -1;
260             mCaller = null;
261             mGroupName = null;
262             logMetricEvent();
263         }
264 
265         /** used for VOL_SET_AVRCP_VOL */
VolumeEvent(int op, int index)266         VolumeEvent(int op, int index) {
267             mOp = op;
268             mVal1 = index;
269             // unused
270             mVal2 = 0;
271             mStream = -1;
272             mCaller = null;
273             mGroupName = null;
274             logMetricEvent();
275         }
276 
277         /** used for VOL_VOICE_ACTIVITY_HEARING_AID */
VolumeEvent(int op, boolean voiceActive, int stream, int index)278         VolumeEvent(int op, boolean voiceActive, int stream, int index) {
279             mOp = op;
280             mStream = stream;
281             mVal1 = index;
282             mVal2 = voiceActive ? 1 : 0;
283             // unused
284             mCaller = null;
285             mGroupName = null;
286             logMetricEvent();
287         }
288 
289         /** used for VOL_MODE_CHANGE_HEARING_AID */
VolumeEvent(int op, int mode, int stream, int index)290         VolumeEvent(int op, int mode, int stream, int index) {
291             mOp = op;
292             mStream = stream;
293             mVal1 = index;
294             mVal2 = mode;
295             // unused
296             mCaller = null;
297             mGroupName = null;
298             logMetricEvent();
299         }
300 
301         /** used for VOL_SET_GROUP_VOL,
302          *           VOL_ADJUST_GROUP_VOL */
VolumeEvent(int op, String group, int index, int flags, String caller)303         VolumeEvent(int op, String group, int index, int flags, String caller) {
304             mOp = op;
305             mStream = -1;
306             mVal1 = index;
307             mVal2 = flags;
308             mCaller = caller;
309             mGroupName = group;
310             logMetricEvent();
311         }
312 
313         /** used for VOL_MUTE_STREAM_INT */
VolumeEvent(int op, int stream, boolean state)314         VolumeEvent(int op, int stream, boolean state) {
315             mOp = op;
316             mStream = stream;
317             mVal1 = state ? 1 : 0;
318             mVal2 = 0;
319             mCaller = null;
320             mGroupName = null;
321             logMetricEvent();
322         }
323 
324 
325         /**
326          * Audio Analytics unique Id.
327          */
328         private static final String mMetricsId = MediaMetrics.Name.AUDIO_VOLUME_EVENT;
329 
330         /**
331          * Log mediametrics event
332          */
logMetricEvent()333         private void logMetricEvent() {
334             switch (mOp) {
335                 case VOL_ADJUST_SUGG_VOL:
336                 case VOL_ADJUST_VOL_UID:
337                 case VOL_ADJUST_STREAM_VOL: {
338                     String eventName;
339                     switch (mOp) {
340                         case VOL_ADJUST_SUGG_VOL:
341                             eventName = "adjustSuggestedStreamVolume";
342                             break;
343                         case VOL_ADJUST_STREAM_VOL:
344                             eventName = "adjustStreamVolume";
345                             break;
346                         case VOL_ADJUST_VOL_UID:
347                             eventName = "adjustStreamVolumeForUid";
348                             break;
349                         default:
350                             return; // not possible, just return here
351                     }
352                     new MediaMetrics.Item(mMetricsId)
353                             .set(MediaMetrics.Property.CALLING_PACKAGE, mCaller)
354                             .set(MediaMetrics.Property.DIRECTION, mVal1 > 0 ? "up" : "down")
355                             .set(MediaMetrics.Property.EVENT, eventName)
356                             .set(MediaMetrics.Property.FLAGS, mVal2)
357                             .set(MediaMetrics.Property.STREAM_TYPE,
358                                     AudioSystem.streamToString(mStream))
359                             .record();
360                     return;
361                 }
362                 case VOL_ADJUST_GROUP_VOL:
363                     new MediaMetrics.Item(mMetricsId)
364                             .set(MediaMetrics.Property.CALLING_PACKAGE, mCaller)
365                             .set(MediaMetrics.Property.DIRECTION, mVal1 > 0 ? "up" : "down")
366                             .set(MediaMetrics.Property.EVENT, "adjustVolumeGroupVolume")
367                             .set(MediaMetrics.Property.FLAGS, mVal2)
368                             .set(MediaMetrics.Property.GROUP, mGroupName)
369                             .record();
370                     return;
371                 case VOL_SET_STREAM_VOL:
372                     new MediaMetrics.Item(mMetricsId)
373                             .set(MediaMetrics.Property.CALLING_PACKAGE, mCaller)
374                             .set(MediaMetrics.Property.EVENT, "setStreamVolume")
375                             .set(MediaMetrics.Property.FLAGS, mVal2)
376                             .set(MediaMetrics.Property.INDEX, mVal1)
377                             .set(MediaMetrics.Property.STREAM_TYPE,
378                                     AudioSystem.streamToString(mStream))
379                             .record();
380                     return;
381                 case VOL_SET_HEARING_AID_VOL:
382                     new MediaMetrics.Item(mMetricsId)
383                             .set(MediaMetrics.Property.EVENT, "setHearingAidVolume")
384                             .set(MediaMetrics.Property.GAIN_DB, (double) mVal2)
385                             .set(MediaMetrics.Property.INDEX, mVal1)
386                             .record();
387                     return;
388                 case VOL_SET_LE_AUDIO_VOL:
389                     new MediaMetrics.Item(mMetricsId)
390                             .set(MediaMetrics.Property.EVENT, "setLeAudioVolume")
391                             .set(MediaMetrics.Property.INDEX, mVal1)
392                             .set(MediaMetrics.Property.MAX_INDEX, mVal2)
393                             .record();
394                     return;
395                 case VOL_SET_AVRCP_VOL:
396                     new MediaMetrics.Item(mMetricsId)
397                             .set(MediaMetrics.Property.EVENT, "setAvrcpVolume")
398                             .set(MediaMetrics.Property.INDEX, mVal1)
399                             .record();
400                     return;
401                 case VOL_VOICE_ACTIVITY_HEARING_AID:
402                     new MediaMetrics.Item(mMetricsId)
403                             .set(MediaMetrics.Property.EVENT, "voiceActivityHearingAid")
404                             .set(MediaMetrics.Property.INDEX, mVal1)
405                             .set(MediaMetrics.Property.STATE,
406                                     mVal2 == 1 ? "active" : "inactive")
407                             .set(MediaMetrics.Property.STREAM_TYPE,
408                                     AudioSystem.streamToString(mStream))
409                             .record();
410                     return;
411                 case VOL_MODE_CHANGE_HEARING_AID:
412                     new MediaMetrics.Item(mMetricsId)
413                             .set(MediaMetrics.Property.EVENT, "modeChangeHearingAid")
414                             .set(MediaMetrics.Property.INDEX, mVal1)
415                             .set(MediaMetrics.Property.MODE, AudioSystem.modeToString(mVal2))
416                             .set(MediaMetrics.Property.STREAM_TYPE,
417                                     AudioSystem.streamToString(mStream))
418                             .record();
419                     return;
420                 case VOL_SET_GROUP_VOL:
421                     new MediaMetrics.Item(mMetricsId)
422                             .set(MediaMetrics.Property.CALLING_PACKAGE, mCaller)
423                             .set(MediaMetrics.Property.EVENT, "setVolumeIndexForAttributes")
424                             .set(MediaMetrics.Property.FLAGS, mVal2)
425                             .set(MediaMetrics.Property.GROUP, mGroupName)
426                             .set(MediaMetrics.Property.INDEX, mVal1)
427                             .record();
428                     return;
429                 case VOL_MUTE_STREAM_INT:
430                     // No value in logging metrics for this internal event
431                     return;
432                 default:
433                     return;
434             }
435         }
436 
437         @Override
eventToString()438         public String eventToString() {
439             switch (mOp) {
440                 case VOL_ADJUST_SUGG_VOL:
441                     return new StringBuilder("adjustSuggestedStreamVolume(sugg:")
442                             .append(AudioSystem.streamToString(mStream))
443                             .append(" dir:").append(AudioManager.adjustToString(mVal1))
444                             .append(" flags:0x").append(Integer.toHexString(mVal2))
445                             .append(") from ").append(mCaller)
446                             .toString();
447                 case VOL_ADJUST_GROUP_VOL:
448                     return new StringBuilder("adjustVolumeGroupVolume(group:")
449                             .append(mGroupName)
450                             .append(" dir:").append(AudioManager.adjustToString(mVal1))
451                             .append(" flags:0x").append(Integer.toHexString(mVal2))
452                             .append(") from ").append(mCaller)
453                             .toString();
454                 case VOL_ADJUST_STREAM_VOL:
455                     return new StringBuilder("adjustStreamVolume(stream:")
456                             .append(AudioSystem.streamToString(mStream))
457                             .append(" dir:").append(AudioManager.adjustToString(mVal1))
458                             .append(" flags:0x").append(Integer.toHexString(mVal2))
459                             .append(") from ").append(mCaller)
460                             .toString();
461                 case VOL_SET_STREAM_VOL:
462                     return new StringBuilder("setStreamVolume(stream:")
463                             .append(AudioSystem.streamToString(mStream))
464                             .append(" index:").append(mVal1)
465                             .append(" flags:0x").append(Integer.toHexString(mVal2))
466                             .append(") from ").append(mCaller)
467                             .toString();
468                 case VOL_SET_HEARING_AID_VOL:
469                     return new StringBuilder("setHearingAidVolume:")
470                             .append(" index:").append(mVal1)
471                             .append(" gain dB:").append(mVal2)
472                             .toString();
473                 case VOL_SET_LE_AUDIO_VOL:
474                     return new StringBuilder("setLeAudioVolume:")
475                             .append(" index:").append(mVal1)
476                             .append(" maxIndex:").append(mVal2)
477                             .toString();
478                 case VOL_SET_AVRCP_VOL:
479                     return new StringBuilder("setAvrcpVolume:")
480                             .append(" index:").append(mVal1)
481                             .toString();
482                 case VOL_ADJUST_VOL_UID:
483                     return new StringBuilder("adjustStreamVolumeForUid(stream:")
484                             .append(AudioSystem.streamToString(mStream))
485                             .append(" dir:").append(AudioManager.adjustToString(mVal1))
486                             .append(" flags:0x").append(Integer.toHexString(mVal2))
487                             .append(") from ").append(mCaller)
488                             .toString();
489                 case VOL_VOICE_ACTIVITY_HEARING_AID:
490                     return new StringBuilder("Voice activity change (")
491                             .append(mVal2 == 1 ? "active" : "inactive")
492                             .append(") causes setting HEARING_AID volume to idx:").append(mVal1)
493                             .append(" stream:").append(AudioSystem.streamToString(mStream))
494                             .toString();
495                 case VOL_MODE_CHANGE_HEARING_AID:
496                     return new StringBuilder("setMode(")
497                             .append(AudioSystem.modeToString(mVal2))
498                             .append(") causes setting HEARING_AID volume to idx:").append(mVal1)
499                             .append(" stream:").append(AudioSystem.streamToString(mStream))
500                             .toString();
501                 case VOL_SET_GROUP_VOL:
502                     return new StringBuilder("setVolumeIndexForAttributes(group:")
503                             .append(" group: ").append(mGroupName)
504                             .append(" index:").append(mVal1)
505                             .append(" flags:0x").append(Integer.toHexString(mVal2))
506                             .append(") from ").append(mCaller)
507                             .toString();
508                 case VOL_MUTE_STREAM_INT:
509                     return new StringBuilder("VolumeStreamState.muteInternally(stream:")
510                             .append(AudioSystem.streamToString(mStream))
511                             .append(mVal1 == 1 ? ", muted)" : ", unmuted)")
512                             .toString();
513                 default: return new StringBuilder("FIXME invalid op:").append(mOp).toString();
514             }
515         }
516     }
517 
518     static final class SoundDoseEvent extends EventLogger.Event {
519         static final int MOMENTARY_EXPOSURE = 0;
520         static final int DOSE_UPDATE = 1;
521         static final int DOSE_REPEAT_5X = 2;
522         static final int DOSE_ACCUMULATION_START = 3;
523         final int mEventType;
524         final float mFloatValue;
525         final long mLongValue;
526 
SoundDoseEvent(int event, float f, long l)527         private SoundDoseEvent(int event, float f, long l) {
528             mEventType = event;
529             mFloatValue = f;
530             mLongValue = l;
531         }
532 
getMomentaryExposureEvent(float mel)533         static SoundDoseEvent getMomentaryExposureEvent(float mel) {
534             return new SoundDoseEvent(MOMENTARY_EXPOSURE, mel, 0 /*ignored*/);
535         }
536 
getDoseUpdateEvent(float csd, long totalDuration)537         static SoundDoseEvent getDoseUpdateEvent(float csd, long totalDuration) {
538             return new SoundDoseEvent(DOSE_UPDATE, csd, totalDuration);
539         }
540 
getDoseRepeat5xEvent()541         static SoundDoseEvent getDoseRepeat5xEvent() {
542             return new SoundDoseEvent(DOSE_REPEAT_5X, 0 /*ignored*/, 0 /*ignored*/);
543         }
544 
getDoseAccumulationStartEvent()545         static SoundDoseEvent getDoseAccumulationStartEvent() {
546             return new SoundDoseEvent(DOSE_ACCUMULATION_START, 0 /*ignored*/, 0 /*ignored*/);
547         }
548 
549         @Override
eventToString()550         public String eventToString() {
551             switch (mEventType) {
552                 case MOMENTARY_EXPOSURE:
553                     return String.format("momentary exposure MEL=%.2f", mFloatValue);
554                 case DOSE_UPDATE:
555                     return String.format(java.util.Locale.US,
556                             "dose update CSD=%.1f%% total duration=%d",
557                             mFloatValue * 100.0f, mLongValue);
558                 case DOSE_REPEAT_5X:
559                     return "CSD reached 500%";
560                 case DOSE_ACCUMULATION_START:
561                     return "CSD accumulating: RS2 entered";
562             }
563             return new StringBuilder("FIXME invalid event type:").append(mEventType).toString();
564         }
565     }
566 
567     /**
568      * Class to log stream type mute/unmute events
569      */
570     static final class StreamMuteEvent extends EventLogger.Event {
571         final int mStreamType;
572         final boolean mMuted;
573         final String mSource;
574 
StreamMuteEvent(int streamType, boolean muted, String source)575         StreamMuteEvent(int streamType, boolean muted, String source) {
576             mStreamType = streamType;
577             mMuted = muted;
578             mSource = source;
579         }
580 
581         @Override
eventToString()582         public String eventToString() {
583             final String streamName =
584                     (mStreamType <= AudioSystem.getNumStreamTypes() && mStreamType >= 0)
585                     ? AudioSystem.STREAM_NAMES[mStreamType]
586                     : ("stream " + mStreamType);
587             return new StringBuilder(streamName)
588                     .append(mMuted ? " muting by " : " unmuting by ")
589                     .append(mSource)
590                     .toString();
591         }
592     }
593 
594     /**
595      * Class to log unmute errors that contradict the ringer/zen mode muted streams
596      */
597     static final class StreamUnmuteErrorEvent extends EventLogger.Event {
598         final int mStreamType;
599         final int mRingerZenMutedStreams;
600 
StreamUnmuteErrorEvent(int streamType, int ringerZenMutedStreams)601         StreamUnmuteErrorEvent(int streamType, int ringerZenMutedStreams) {
602             mStreamType = streamType;
603             mRingerZenMutedStreams = ringerZenMutedStreams;
604         }
605 
606         @Override
eventToString()607         public String eventToString() {
608             final String streamName =
609                     (mStreamType <= AudioSystem.getNumStreamTypes() && mStreamType >= 0)
610                             ? AudioSystem.STREAM_NAMES[mStreamType]
611                             : ("stream " + mStreamType);
612             return new StringBuilder("Invalid call to unmute ")
613                     .append(streamName)
614                     .append(" despite muted streams 0x")
615                     .append(Integer.toHexString(mRingerZenMutedStreams))
616                     .toString();
617         }
618     }
619 
620     static final class RingerZenMutedStreamsEvent extends EventLogger.Event {
621         final int mRingerZenMutedStreams;
622         final String mSource;
623 
RingerZenMutedStreamsEvent(int ringerZenMutedStreams, String source)624         RingerZenMutedStreamsEvent(int ringerZenMutedStreams, String source) {
625             mRingerZenMutedStreams = ringerZenMutedStreams;
626             mSource = source;
627         }
628 
629         @Override
eventToString()630         public String eventToString() {
631             return new StringBuilder("RingerZenMutedStreams 0x")
632                     .append(Integer.toHexString(mRingerZenMutedStreams))
633                     .append(" from ").append(mSource)
634                     .toString();
635         }
636     }
637 }
638