1 /*
2  * Copyright (C) 2015 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.volume;
18 
19 import android.media.AudioManager;
20 import android.media.AudioSystem;
21 import android.provider.Settings.Global;
22 import android.util.Log;
23 
24 import com.android.internal.annotations.VisibleForTesting;
25 import com.android.internal.logging.MetricsLogger;
26 import com.android.internal.logging.UiEvent;
27 import com.android.internal.logging.UiEventLogger;
28 import com.android.internal.logging.UiEventLoggerImpl;
29 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
30 import com.android.systemui.plugins.VolumeDialogController.State;
31 
32 import java.util.Arrays;
33 
34 /**
35  *  Interesting events related to the volume.
36  */
37 public class Events {
38     private static final String TAG = Util.logTag(Events.class);
39 
40     public static final int EVENT_SHOW_DIALOG = 0;  // (reason|int) (keyguard|bool)
41     public static final int EVENT_DISMISS_DIALOG = 1; // (reason|int)
42     public static final int EVENT_ACTIVE_STREAM_CHANGED = 2; // (stream|int)
43     public static final int EVENT_EXPAND = 3; // (expand|bool)
44     public static final int EVENT_KEY = 4; // (stream|int) (lastAudibleStreamVolume)
45     public static final int EVENT_COLLECTION_STARTED = 5;
46     public static final int EVENT_COLLECTION_STOPPED = 6;
47     public static final int EVENT_ICON_CLICK = 7; // (stream|int) (icon_state|int)
48     public static final int EVENT_SETTINGS_CLICK = 8;
49     public static final int EVENT_TOUCH_LEVEL_CHANGED = 9; // (stream|int) (level|int)
50     public static final int EVENT_LEVEL_CHANGED = 10; // (stream|int) (level|int)
51     public static final int EVENT_INTERNAL_RINGER_MODE_CHANGED = 11; // (mode|int)
52     public static final int EVENT_EXTERNAL_RINGER_MODE_CHANGED = 12; // (mode|int)
53     public static final int EVENT_ZEN_MODE_CHANGED = 13; // (mode|int)
54     public static final int EVENT_SUPPRESSOR_CHANGED = 14;  // (component|string) (name|string)
55     public static final int EVENT_MUTE_CHANGED = 15;  // (stream|int) (muted|bool)
56     public static final int EVENT_TOUCH_LEVEL_DONE = 16;  // (stream|int) (level|int)
57     public static final int EVENT_ZEN_CONFIG_CHANGED = 17; // (allow/disallow|string)
58     public static final int EVENT_RINGER_TOGGLE = 18; // (ringer_mode)
59     public static final int EVENT_SHOW_USB_OVERHEAT_ALARM = 19; // (reason|int) (keyguard|bool)
60     public static final int EVENT_DISMISS_USB_OVERHEAT_ALARM = 20; // (reason|int) (keyguard|bool)
61     public static final int EVENT_ODI_CAPTIONS_CLICK = 21;
62     public static final int EVENT_ODI_CAPTIONS_TOOLTIP_CLICK = 22;
63     public static final int EVENT_SLIDER_TOUCH_TRACKING = 23; // (tracking|bool)
64 
65     private static final String[] EVENT_TAGS = {
66             "show_dialog",
67             "dismiss_dialog",
68             "active_stream_changed",
69             "expand",
70             "key",
71             "collection_started",
72             "collection_stopped",
73             "icon_click",
74             "settings_click",
75             "touch_level_changed",
76             "level_changed",
77             "internal_ringer_mode_changed",
78             "external_ringer_mode_changed",
79             "zen_mode_changed",
80             "suppressor_changed",
81             "mute_changed",
82             "touch_level_done",
83             "zen_mode_config_changed",
84             "ringer_toggle",
85             "show_usb_overheat_alarm",
86             "dismiss_usb_overheat_alarm",
87             "odi_captions_click",
88             "odi_captions_tooltip_click",
89             "slider_touch_tracking"
90     };
91 
92     public static final int DISMISS_REASON_UNKNOWN = 0;
93     public static final int DISMISS_REASON_TOUCH_OUTSIDE = 1;
94     public static final int DISMISS_REASON_VOLUME_CONTROLLER = 2;
95     public static final int DISMISS_REASON_TIMEOUT = 3;
96     public static final int DISMISS_REASON_SCREEN_OFF = 4;
97     public static final int DISMISS_REASON_SETTINGS_CLICKED = 5;
98     public static final int DISMISS_REASON_DONE_CLICKED = 6;
99     public static final int DISMISS_STREAM_GONE = 7;
100     public static final int DISMISS_REASON_OUTPUT_CHOOSER = 8;
101     public static final int DISMISS_REASON_USB_OVERHEAD_ALARM_CHANGED = 9;
102     public static final int DISMISS_REASON_CSD_WARNING_TIMEOUT = 10;
103     public static final int DISMISS_REASON_POSTURE_CHANGED = 11;
104 
105     public static final String[] DISMISS_REASONS = {
106             "unknown",
107             "touch_outside",
108             "volume_controller",
109             "timeout",
110             "screen_off",
111             "settings_clicked",
112             "done_clicked",
113             "a11y_stream_changed",
114             "output_chooser",
115             "usb_temperature_below_threshold",
116             "csd_warning_timeout",
117             "posture_changed"
118     };
119 
120     public static final int SHOW_REASON_UNKNOWN = 0;
121     public static final int SHOW_REASON_VOLUME_CHANGED = 1;
122     public static final int SHOW_REASON_REMOTE_VOLUME_CHANGED = 2;
123     public static final int SHOW_REASON_USB_OVERHEAD_ALARM_CHANGED = 3;
124     public static final String[] SHOW_REASONS = {
125         "unknown",
126         "volume_changed",
127         "remote_volume_changed",
128         "usb_temperature_above_threshold"
129     };
130 
131     public static final int ICON_STATE_UNKNOWN = 0;
132     public static final int ICON_STATE_UNMUTE = 1;
133     public static final int ICON_STATE_MUTE = 2;
134     public static final int ICON_STATE_VIBRATE = 3;
135 
136     @VisibleForTesting
137     public enum VolumeDialogOpenEvent implements UiEventLogger.UiEventEnum {
138         //TODO zap the lock/unlock distinction
139         INVALID(0),
140         @UiEvent(doc = "The volume dialog was shown because the volume changed")
141         VOLUME_DIALOG_SHOW_VOLUME_CHANGED(128),
142         @UiEvent(doc = "The volume dialog was shown because the volume changed remotely")
143         VOLUME_DIALOG_SHOW_REMOTE_VOLUME_CHANGED(129),
144         @UiEvent(doc = "The volume dialog was shown because the usb high temperature alarm changed")
145         VOLUME_DIALOG_SHOW_USB_TEMP_ALARM_CHANGED(130);
146 
147         private final int mId;
VolumeDialogOpenEvent(int id)148         VolumeDialogOpenEvent(int id) {
149             mId = id;
150         }
getId()151         public int getId() {
152             return mId;
153         }
fromReasons(int reason)154         static VolumeDialogOpenEvent fromReasons(int reason) {
155             switch (reason) {
156                 case SHOW_REASON_VOLUME_CHANGED:
157                     return VOLUME_DIALOG_SHOW_VOLUME_CHANGED;
158                 case SHOW_REASON_REMOTE_VOLUME_CHANGED:
159                     return VOLUME_DIALOG_SHOW_REMOTE_VOLUME_CHANGED;
160                 case SHOW_REASON_USB_OVERHEAD_ALARM_CHANGED:
161                     return VOLUME_DIALOG_SHOW_USB_TEMP_ALARM_CHANGED;
162             }
163             return INVALID;
164         }
165     }
166 
167     @VisibleForTesting
168     public enum VolumeDialogCloseEvent implements UiEventLogger.UiEventEnum {
169         INVALID(0),
170         @UiEvent(doc = "The volume dialog was dismissed because of a touch outside the dialog")
171         VOLUME_DIALOG_DISMISS_TOUCH_OUTSIDE(134),
172         @UiEvent(doc = "The system asked the volume dialog to close, e.g. for a navigation bar "
173                  + "touch, or ActivityManager ACTION_CLOSE_SYSTEM_DIALOGS broadcast.")
174         VOLUME_DIALOG_DISMISS_SYSTEM(135),
175         @UiEvent(doc = "The volume dialog was dismissed because it timed out")
176         VOLUME_DIALOG_DISMISS_TIMEOUT(136),
177         @UiEvent(doc = "The volume dialog was dismissed because the screen turned off")
178         VOLUME_DIALOG_DISMISS_SCREEN_OFF(137),
179         @UiEvent(doc = "The volume dialog was dismissed because the settings icon was clicked")
180         VOLUME_DIALOG_DISMISS_SETTINGS(138),
181         // reserving 139 for DISMISS_REASON_DONE_CLICKED which is currently unused
182         @UiEvent(doc = "The volume dialog was dismissed because the stream no longer exists")
183         VOLUME_DIALOG_DISMISS_STREAM_GONE(140),
184         // reserving 141 for DISMISS_REASON_OUTPUT_CHOOSER which is currently unused
185         @UiEvent(doc = "The volume dialog was dismissed because the usb high temperature alarm "
186                  + "changed")
187         VOLUME_DIALOG_DISMISS_USB_TEMP_ALARM_CHANGED(142);
188 
189         private final int mId;
VolumeDialogCloseEvent(int id)190         VolumeDialogCloseEvent(int id) {
191             mId = id;
192         }
getId()193         public int getId() {
194             return mId;
195         }
196 
fromReason(int reason)197         static VolumeDialogCloseEvent fromReason(int reason) {
198             switch (reason) {
199                 case DISMISS_REASON_TOUCH_OUTSIDE:
200                     return VOLUME_DIALOG_DISMISS_TOUCH_OUTSIDE;
201                 case DISMISS_REASON_VOLUME_CONTROLLER:
202                     return VOLUME_DIALOG_DISMISS_SYSTEM;
203                 case DISMISS_REASON_TIMEOUT:
204                     return VOLUME_DIALOG_DISMISS_TIMEOUT;
205                 case DISMISS_REASON_SCREEN_OFF:
206                     return VOLUME_DIALOG_DISMISS_SCREEN_OFF;
207                 case DISMISS_REASON_SETTINGS_CLICKED:
208                     return VOLUME_DIALOG_DISMISS_SETTINGS;
209                 case DISMISS_STREAM_GONE:
210                     return VOLUME_DIALOG_DISMISS_STREAM_GONE;
211                 case DISMISS_REASON_USB_OVERHEAD_ALARM_CHANGED:
212                     return VOLUME_DIALOG_DISMISS_USB_TEMP_ALARM_CHANGED;
213             }
214             return INVALID;
215         }
216     }
217 
218     @VisibleForTesting
219     public enum VolumeDialogEvent implements UiEventLogger.UiEventEnum {
220         INVALID(0),
221         @UiEvent(doc = "The volume dialog settings icon was clicked")
222         VOLUME_DIALOG_SETTINGS_CLICK(143),
223         @UiEvent(doc = "The volume dialog details were expanded")
224         VOLUME_DIALOG_EXPAND_DETAILS(144),
225         @UiEvent(doc = "The volume dialog details were collapsed")
226         VOLUME_DIALOG_COLLAPSE_DETAILS(145),
227         @UiEvent(doc = "The active audio stream changed")
228         VOLUME_DIALOG_ACTIVE_STREAM_CHANGED(146),
229         @UiEvent(doc = "The audio stream was muted via icon")
230         VOLUME_DIALOG_MUTE_STREAM(147),
231         @UiEvent(doc = "The audio stream was unmuted via icon")
232         VOLUME_DIALOG_UNMUTE_STREAM(148),
233         @UiEvent(doc = "The audio stream was set to vibrate via icon")
234         VOLUME_DIALOG_TO_VIBRATE_STREAM(149),
235         @UiEvent(doc = "The audio stream was set to non-silent via slider")
236         VOLUME_DIALOG_SLIDER(150),
237         @UiEvent(doc = "The audio stream was set to silent via slider")
238         VOLUME_DIALOG_SLIDER_TO_ZERO(151),
239         @UiEvent(doc = "The right-most slider started tracking touch")
240         VOLUME_DIALOG_SLIDER_STARTED_TRACKING_TOUCH(1620),
241         @UiEvent(doc = "The right-most slider stopped tracking touch")
242         VOLUME_DIALOG_SLIDER_STOPPED_TRACKING_TOUCH(1621),
243         @UiEvent(doc = "ODI captions was clicked")
244         VOLUME_DIALOG_ODI_CAPTIONS_CLICKED(1503),
245         @UiEvent(doc = "ODI captions tooltip dismiss was clicked")
246         VOLUME_DIALOG_ODI_CAPTIONS_TOOLTIP_CLICKED(1504),
247         @UiEvent(doc = "The audio volume was adjusted to silent via key")
248         VOLUME_KEY_TO_ZERO(152),
249         @UiEvent(doc = "The audio volume was adjusted to non-silent via key")
250         VOLUME_KEY(153),
251         @UiEvent(doc = "The ringer mode was toggled to silent")
252         RINGER_MODE_SILENT(154),
253         @UiEvent(doc = "The ringer mode was toggled to vibrate")
254         RINGER_MODE_VIBRATE(155),
255         @UiEvent(doc = "The ringer mode was toggled to normal")
256         RINGER_MODE_NORMAL(334),
257         @UiEvent(doc = "USB Overheat alarm was raised")
258         USB_OVERHEAT_ALARM(160),
259         @UiEvent(doc = "USB Overheat alarm was dismissed")
260         USB_OVERHEAT_ALARM_DISMISSED(161);
261 
262         private final int mId;
263 
VolumeDialogEvent(int id)264         VolumeDialogEvent(int id) {
265             mId = id;
266         }
267 
getId()268         public int getId() {
269             return mId;
270         }
271 
fromIconState(int iconState)272         static VolumeDialogEvent fromIconState(int iconState) {
273             switch (iconState) {
274                 case ICON_STATE_UNMUTE:
275                     return VOLUME_DIALOG_UNMUTE_STREAM;
276                 case ICON_STATE_MUTE:
277                     return VOLUME_DIALOG_MUTE_STREAM;
278                 case ICON_STATE_VIBRATE:
279                     return VOLUME_DIALOG_TO_VIBRATE_STREAM;
280                 default:
281                     return INVALID;
282             }
283         }
284 
fromSliderLevel(int level)285         static VolumeDialogEvent fromSliderLevel(int level) {
286             return level == 0 ? VOLUME_DIALOG_SLIDER_TO_ZERO : VOLUME_DIALOG_SLIDER;
287         }
288 
fromKeyLevel(int level)289         static VolumeDialogEvent fromKeyLevel(int level) {
290             return level == 0 ? VOLUME_KEY_TO_ZERO : VOLUME_KEY;
291         }
292 
fromRingerMode(int ringerMode)293         static VolumeDialogEvent fromRingerMode(int ringerMode) {
294             switch (ringerMode) {
295                 case AudioManager.RINGER_MODE_SILENT:
296                     return RINGER_MODE_SILENT;
297                 case AudioManager.RINGER_MODE_VIBRATE:
298                     return RINGER_MODE_VIBRATE;
299                 case AudioManager.RINGER_MODE_NORMAL:
300                     return RINGER_MODE_NORMAL;
301                 default:
302                     return INVALID;
303             }
304         }
305     }
306 
307     @VisibleForTesting
308     public enum ZenModeEvent implements UiEventLogger.UiEventEnum {
309         INVALID(0),
310         @UiEvent(doc = "Zen (do not disturb) mode was toggled to off")
311         ZEN_MODE_OFF(335),
312         @UiEvent(doc = "Zen (do not disturb) mode was toggled to important interruptions only")
313         ZEN_MODE_IMPORTANT_ONLY(157),
314         @UiEvent(doc = "Zen (do not disturb) mode was toggled to alarms only")
315         ZEN_MODE_ALARMS_ONLY(158),
316         @UiEvent(doc = "Zen (do not disturb) mode was toggled to block all interruptions")
317         ZEN_MODE_NO_INTERRUPTIONS(159);
318 
319         private final int mId;
ZenModeEvent(int id)320         ZenModeEvent(int id) {
321             mId = id;
322         }
getId()323         public int getId() {
324             return mId;
325         }
326 
fromZenMode(int zenMode)327         static ZenModeEvent fromZenMode(int zenMode) {
328             switch (zenMode) {
329                 case Global.ZEN_MODE_OFF: return ZEN_MODE_OFF;
330                 case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS: return ZEN_MODE_IMPORTANT_ONLY;
331                 case Global.ZEN_MODE_ALARMS: return ZEN_MODE_ALARMS_ONLY;
332                 case Global.ZEN_MODE_NO_INTERRUPTIONS: return ZEN_MODE_NO_INTERRUPTIONS;
333                 default: return INVALID;
334             }
335         }
336     }
337 
338     public static Callback sCallback;
339     @VisibleForTesting
340     static MetricsLogger sLegacyLogger = new MetricsLogger();
341     @VisibleForTesting
342     static UiEventLogger sUiEventLogger = new UiEventLoggerImpl();
343 
344     /**
345      * Logs an event to the system log, to sCallback if present, and to the logEvent destinations.
346      * @param tag One of the EVENT_* codes above.
347      * @param list Any additional event-specific arguments, documented above.
348      */
writeEvent(int tag, Object... list)349     public static void writeEvent(int tag, Object... list) {
350         final long time = System.currentTimeMillis();
351         Log.i(TAG, logEvent(tag, list));
352         if (sCallback != null) {
353             sCallback.writeEvent(time, tag, list);
354         }
355     }
356 
357     /**
358      * Logs an event to the event log and UiEvent (statsd) logging. Compare writeEvent, which
359      * adds more log destinations.
360      * @param tag One of the EVENT_* codes above.
361      * @param list Any additional event-specific arguments, documented above.
362      * @return String a readable description of the event.  Begins "writeEvent <tag_description>"
363      * if the tag is valid.
364      */
logEvent(int tag, Object... list)365     public static String logEvent(int tag, Object... list) {
366         if (tag >= EVENT_TAGS.length) {
367             return "";
368         }
369         final StringBuilder sb = new StringBuilder("writeEvent ").append(EVENT_TAGS[tag]);
370         // Handle events without extra data
371         if (list == null || list.length == 0) {
372             if (tag == EVENT_SETTINGS_CLICK) {
373                 sLegacyLogger.action(MetricsEvent.ACTION_VOLUME_SETTINGS);
374                 sUiEventLogger.log(VolumeDialogEvent.VOLUME_DIALOG_SETTINGS_CLICK);
375             } else if (tag == EVENT_ODI_CAPTIONS_CLICK) {
376                 sUiEventLogger.log(VolumeDialogEvent.VOLUME_DIALOG_ODI_CAPTIONS_CLICKED);
377             } else if (tag == EVENT_ODI_CAPTIONS_TOOLTIP_CLICK) {
378                 sUiEventLogger.log(VolumeDialogEvent.VOLUME_DIALOG_ODI_CAPTIONS_TOOLTIP_CLICKED);
379             }
380             return sb.toString();
381         }
382         // Handle events with extra data. We've established list[0] exists.
383         sb.append(" ");
384         switch (tag) {
385             case EVENT_SHOW_DIALOG:
386                 sLegacyLogger.visible(MetricsEvent.VOLUME_DIALOG);
387                 if (list.length > 1) {
388                     final Integer reason = (Integer) list[0];
389                     final Boolean keyguard = (Boolean) list[1];
390                     sLegacyLogger.histogram("volume_from_keyguard", keyguard ? 1 : 0);
391                     sUiEventLogger.log(VolumeDialogOpenEvent.fromReasons(reason));
392                     sb.append(SHOW_REASONS[reason]).append(" keyguard=").append(keyguard);
393                 }
394                 break;
395             case EVENT_EXPAND: {
396                 final Boolean expand = (Boolean) list[0];
397                 sLegacyLogger.visibility(MetricsEvent.VOLUME_DIALOG_DETAILS, expand);
398                 sUiEventLogger.log(expand ? VolumeDialogEvent.VOLUME_DIALOG_EXPAND_DETAILS
399                         : VolumeDialogEvent.VOLUME_DIALOG_COLLAPSE_DETAILS);
400                 sb.append(expand);
401                 break;
402             }
403             case EVENT_DISMISS_DIALOG: {
404                 sLegacyLogger.hidden(MetricsEvent.VOLUME_DIALOG);
405                 final Integer reason = (Integer) list[0];
406                 sUiEventLogger.log(VolumeDialogCloseEvent.fromReason(reason));
407                 sb.append(DISMISS_REASONS[reason]);
408                 break;
409             }
410             case EVENT_ACTIVE_STREAM_CHANGED: {
411                 final Integer stream = (Integer) list[0];
412                 sLegacyLogger.action(MetricsEvent.ACTION_VOLUME_STREAM, stream);
413                 sUiEventLogger.log(VolumeDialogEvent.VOLUME_DIALOG_ACTIVE_STREAM_CHANGED);
414                 sb.append(AudioSystem.streamToString(stream));
415                 break;
416             }
417             case EVENT_ICON_CLICK:
418                 if (list.length > 1) {
419                     final Integer stream = (Integer) list[0];
420                     sLegacyLogger.action(MetricsEvent.ACTION_VOLUME_ICON, stream);
421                     final Integer iconState = (Integer) list[1];
422                     sUiEventLogger.log(VolumeDialogEvent.fromIconState(iconState));
423                     sb.append(AudioSystem.streamToString(stream)).append(' ')
424                             .append(iconStateToString(iconState));
425                 }
426                 break;
427             case EVENT_TOUCH_LEVEL_DONE: // (stream|int) (level|int)
428                 if (list.length > 1) {
429                     final Integer level = (Integer) list[1];
430                     sLegacyLogger.action(MetricsEvent.ACTION_VOLUME_SLIDER, level);
431                     sUiEventLogger.log(VolumeDialogEvent.fromSliderLevel(level));
432                 }
433                 // fall through
434             case EVENT_TOUCH_LEVEL_CHANGED:
435             case EVENT_LEVEL_CHANGED:
436             case EVENT_MUTE_CHANGED:  // (stream|int) (level|int)
437                 if (list.length > 1) {
438                     sb.append(AudioSystem.streamToString((Integer) list[0])).append(' ')
439                             .append(list[1]);
440                 }
441                 break;
442             case EVENT_KEY: // (stream|int) (lastAudibleStreamVolume)
443                 if (list.length > 1) {
444                     final Integer stream = (Integer) list[0];
445                     sLegacyLogger.action(MetricsEvent.ACTION_VOLUME_KEY, stream);
446                     final Integer level = (Integer) list[1];
447                     sUiEventLogger.log(VolumeDialogEvent.fromKeyLevel(level));
448                     sb.append(AudioSystem.streamToString(stream)).append(' ').append(level);
449                 }
450                 break;
451             case EVENT_RINGER_TOGGLE: {
452                 final Integer ringerMode = (Integer) list[0];
453                 sLegacyLogger.action(MetricsEvent.ACTION_VOLUME_RINGER_TOGGLE, ringerMode);
454                 sUiEventLogger.log(VolumeDialogEvent.fromRingerMode(ringerMode));
455                 sb.append(ringerModeToString(ringerMode));
456                 break;
457             }
458             case EVENT_EXTERNAL_RINGER_MODE_CHANGED: {
459                 final Integer ringerMode = (Integer) list[0];
460                 sLegacyLogger.action(MetricsEvent.ACTION_RINGER_MODE, ringerMode);
461             }
462                 // fall through
463             case EVENT_INTERNAL_RINGER_MODE_CHANGED: {
464                 final Integer ringerMode = (Integer) list[0];
465                 sb.append(ringerModeToString(ringerMode));
466                 break;
467             }
468             case EVENT_ZEN_MODE_CHANGED: {
469                 final Integer zenMode = (Integer) list[0];
470                 sb.append(zenModeToString(zenMode));
471                 sUiEventLogger.log(ZenModeEvent.fromZenMode(zenMode));
472                 break;
473             }
474             case EVENT_SUPPRESSOR_CHANGED:  // (component|string) (name|string)
475                 if (list.length > 1) {
476                     sb.append(list[0]).append(' ').append(list[1]);
477                 }
478                 break;
479             case EVENT_SHOW_USB_OVERHEAT_ALARM:
480                 sLegacyLogger.visible(MetricsEvent.POWER_OVERHEAT_ALARM);
481                 sUiEventLogger.log(VolumeDialogEvent.USB_OVERHEAT_ALARM);
482                 if (list.length > 1) {
483                     final Boolean keyguard = (Boolean) list[1];
484                     sLegacyLogger.histogram("show_usb_overheat_alarm", keyguard ? 1 : 0);
485                     final Integer reason = (Integer) list[0];
486                     sb.append(SHOW_REASONS[reason]).append(" keyguard=").append(keyguard);
487                 }
488                 break;
489             case EVENT_DISMISS_USB_OVERHEAT_ALARM:
490                 sLegacyLogger.hidden(MetricsEvent.POWER_OVERHEAT_ALARM);
491                 sUiEventLogger.log(VolumeDialogEvent.USB_OVERHEAT_ALARM_DISMISSED);
492                 if (list.length > 1) {
493                     final Boolean keyguard = (Boolean) list[1];
494                     sLegacyLogger.histogram("dismiss_usb_overheat_alarm", keyguard ? 1 : 0);
495                     final Integer reason = (Integer) list[0];
496                     sb.append(DISMISS_REASONS[reason])
497                             .append(" keyguard=").append(keyguard);
498                 }
499                 break;
500             case EVENT_SLIDER_TOUCH_TRACKING:
501                 final boolean startedTracking = (boolean) list[0];
502                 final VolumeDialogEvent event;
503                 if (startedTracking) {
504                     event = VolumeDialogEvent.VOLUME_DIALOG_SLIDER_STARTED_TRACKING_TOUCH;
505                 } else {
506                     event = VolumeDialogEvent.VOLUME_DIALOG_SLIDER_STOPPED_TRACKING_TOUCH;
507                 }
508                 sUiEventLogger.log(event);
509             default:
510                 sb.append(Arrays.asList(list));
511                 break;
512         }
513         return sb.toString();
514     }
515 
writeState(long time, State state)516     public static void writeState(long time, State state) {
517         if (sCallback != null) {
518             sCallback.writeState(time, state);
519         }
520     }
521 
iconStateToString(int iconState)522     private static String iconStateToString(int iconState) {
523         switch (iconState) {
524             case ICON_STATE_UNMUTE: return "unmute";
525             case ICON_STATE_MUTE: return "mute";
526             case ICON_STATE_VIBRATE: return "vibrate";
527             default: return "unknown_state_" + iconState;
528         }
529     }
530 
ringerModeToString(int ringerMode)531     private static String ringerModeToString(int ringerMode) {
532         switch (ringerMode) {
533             case AudioManager.RINGER_MODE_SILENT: return "silent";
534             case AudioManager.RINGER_MODE_VIBRATE: return "vibrate";
535             case AudioManager.RINGER_MODE_NORMAL: return "normal";
536             default: return "unknown";
537         }
538     }
539 
zenModeToString(int zenMode)540     private static String zenModeToString(int zenMode) {
541         switch (zenMode) {
542             case Global.ZEN_MODE_OFF: return "off";
543             case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS: return "important_interruptions";
544             case Global.ZEN_MODE_ALARMS: return "alarms";
545             case Global.ZEN_MODE_NO_INTERRUPTIONS: return "no_interruptions";
546             default: return "unknown";
547         }
548     }
549 
550     public interface Callback {
writeEvent(long time, int tag, Object[] list)551         void writeEvent(long time, int tag, Object[] list);
writeState(long time, State state)552         void writeState(long time, State state);
553     }
554 
555 }
556