Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 19db476a authored by Will Brockman's avatar Will Brockman
Browse files

Add UiEvent logging to volume dialog Events.

Minor refactoring of Events.writeEvent() for testability.

Also added unit test for Events class, covering all 3 types of logging
it does.

Test: atest SystemUITests
Test: mp droid + statsd_testdrive verify UiEvent logging.
Change-Id: Id1cd0e0f5aa9082dab5d85144ea62ed77a36eacd
parent 654af761
Loading
Loading
Loading
Loading
+350 −86
Original line number Diff line number Diff line
@@ -21,7 +21,11 @@ import android.media.AudioSystem;
import android.provider.Settings.Global;
import android.util.Log;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.UiEvent;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.logging.UiEventLoggerImpl;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.plugins.VolumeDialogController.State;

@@ -37,7 +41,7 @@ public class Events {
    public static final int EVENT_DISMISS_DIALOG = 1; // (reason|int)
    public static final int EVENT_ACTIVE_STREAM_CHANGED = 2; // (stream|int)
    public static final int EVENT_EXPAND = 3; // (expand|bool)
    public static final int EVENT_KEY = 4;
    public static final int EVENT_KEY = 4; // (stream|int) (lastAudibleStreamVolume)
    public static final int EVENT_COLLECTION_STARTED = 5;
    public static final int EVENT_COLLECTION_STOPPED = 6;
    public static final int EVENT_ICON_CLICK = 7; // (stream|int) (icon_state|int)
@@ -49,7 +53,7 @@ public class Events {
    public static final int EVENT_ZEN_MODE_CHANGED = 13; // (mode|int)
    public static final int EVENT_SUPPRESSOR_CHANGED = 14;  // (component|string) (name|string)
    public static final int EVENT_MUTE_CHANGED = 15;  // (stream|int) (muted|bool)
    public static final int EVENT_TOUCH_LEVEL_DONE = 16;  // (stream|int) (level|bool)
    public static final int EVENT_TOUCH_LEVEL_DONE = 16;  // (stream|int) (level|int)
    public static final int EVENT_ZEN_CONFIG_CHANGED = 17; // (allow/disallow|string)
    public static final int EVENT_RINGER_TOGGLE = 18; // (ringer_mode)
    public static final int EVENT_SHOW_USB_OVERHEAT_ALARM = 19; // (reason|int) (keyguard|bool)
@@ -122,103 +126,363 @@ public class Events {
    public static final int ICON_STATE_MUTE = 2;
    public static final int ICON_STATE_VIBRATE = 3;

    @VisibleForTesting
    public enum VolumeDialogOpenEvent implements UiEventLogger.UiEventEnum {
        //TODO zap the lock/unlock distinction
        INVALID(0),
        @UiEvent(doc = "The volume dialog was shown because the volume changed")
        VOLUME_DIALOG_SHOW_VOLUME_CHANGED(128),
        @UiEvent(doc = "The volume dialog was shown because the volume changed remotely")
        VOLUME_DIALOG_SHOW_REMOTE_VOLUME_CHANGED(129),
        @UiEvent(doc = "The volume dialog was shown because the usb high temperature alarm changed")
        VOLUME_DIALOG_SHOW_USB_TEMP_ALARM_CHANGED(130);

        private final int mId;
        VolumeDialogOpenEvent(int id) {
            mId = id;
        }
        public int getId() {
            return mId;
        }
        static VolumeDialogOpenEvent fromReasons(int reason) {
            switch (reason) {
                case SHOW_REASON_VOLUME_CHANGED:
                    return VOLUME_DIALOG_SHOW_VOLUME_CHANGED;
                case SHOW_REASON_REMOTE_VOLUME_CHANGED:
                    return VOLUME_DIALOG_SHOW_REMOTE_VOLUME_CHANGED;
                case SHOW_REASON_USB_OVERHEAD_ALARM_CHANGED:
                    return VOLUME_DIALOG_SHOW_USB_TEMP_ALARM_CHANGED;
            }
            return INVALID;
        }
    }

    @VisibleForTesting
    public enum VolumeDialogCloseEvent implements UiEventLogger.UiEventEnum {
        INVALID(0),
        @UiEvent(doc = "The volume dialog was dismissed because of a touch outside the dialog")
        VOLUME_DIALOG_DISMISS_TOUCH_OUTSIDE(134),
        @UiEvent(doc = "The system asked the volume dialog to close, e.g. for a navigation bar "
                 + "touch, or ActivityManager ACTION_CLOSE_SYSTEM_DIALOGS broadcast.")
        VOLUME_DIALOG_DISMISS_SYSTEM(135),
        @UiEvent(doc = "The volume dialog was dismissed because it timed out")
        VOLUME_DIALOG_DISMISS_TIMEOUT(136),
        @UiEvent(doc = "The volume dialog was dismissed because the screen turned off")
        VOLUME_DIALOG_DISMISS_SCREEN_OFF(137),
        @UiEvent(doc = "The volume dialog was dismissed because the settings icon was clicked")
        VOLUME_DIALOG_DISMISS_SETTINGS(138),
        // reserving 139 for DISMISS_REASON_DONE_CLICKED which is currently unused
        @UiEvent(doc = "The volume dialog was dismissed because the stream no longer exists")
        VOLUME_DIALOG_DISMISS_STREAM_GONE(140),
        // reserving 141 for DISMISS_REASON_OUTPUT_CHOOSER which is currently unused
        @UiEvent(doc = "The volume dialog was dismissed because the usb high temperature alarm "
                 + "changed")
        VOLUME_DIALOG_DISMISS_USB_TEMP_ALARM_CHANGED(142);

        private final int mId;
        VolumeDialogCloseEvent(int id) {
            mId = id;
        }
        public int getId() {
            return mId;
        }

        static VolumeDialogCloseEvent fromReason(int reason) {
            switch (reason) {
                case DISMISS_REASON_TOUCH_OUTSIDE:
                    return VOLUME_DIALOG_DISMISS_TOUCH_OUTSIDE;
                case DISMISS_REASON_VOLUME_CONTROLLER:
                    return VOLUME_DIALOG_DISMISS_SYSTEM;
                case DISMISS_REASON_TIMEOUT:
                    return VOLUME_DIALOG_DISMISS_TIMEOUT;
                case DISMISS_REASON_SCREEN_OFF:
                    return VOLUME_DIALOG_DISMISS_SCREEN_OFF;
                case DISMISS_REASON_SETTINGS_CLICKED:
                    return VOLUME_DIALOG_DISMISS_SETTINGS;
                case DISMISS_STREAM_GONE:
                    return VOLUME_DIALOG_DISMISS_STREAM_GONE;
                case DISMISS_REASON_USB_OVERHEAD_ALARM_CHANGED:
                    return VOLUME_DIALOG_DISMISS_USB_TEMP_ALARM_CHANGED;
            }
            return INVALID;
        }
    }

    @VisibleForTesting
    public enum VolumeDialogEvent implements UiEventLogger.UiEventEnum {
        INVALID(0),
        @UiEvent(doc = "The volume dialog settings icon was clicked")
        VOLUME_DIALOG_SETTINGS_CLICK(143),
        @UiEvent(doc = "The volume dialog details were expanded")
        VOLUME_DIALOG_EXPAND_DETAILS(144),
        @UiEvent(doc = "The volume dialog details were collapsed")
        VOLUME_DIALOG_COLLAPSE_DETAILS(145),
        @UiEvent(doc = "The active audio stream changed")
        VOLUME_DIALOG_ACTIVE_STREAM_CHANGED(146),
        @UiEvent(doc = "The audio stream was muted via icon")
        VOLUME_DIALOG_MUTE_STREAM(147),
        @UiEvent(doc = "The audio stream was unmuted via icon")
        VOLUME_DIALOG_UNMUTE_STREAM(148),
        @UiEvent(doc = "The audio stream was set to vibrate via icon")
        VOLUME_DIALOG_TO_VIBRATE_STREAM(149),
        @UiEvent(doc = "The audio stream was set to non-silent via slider")
        VOLUME_DIALOG_SLIDER(150),
        @UiEvent(doc = "The audio stream was set to silent via slider")
        VOLUME_DIALOG_SLIDER_TO_ZERO(151),
        @UiEvent(doc = "The audio volume was adjusted to silent via key")
        VOLUME_KEY_TO_ZERO(152),
        @UiEvent(doc = "The audio volume was adjusted to non-silent via key")
        VOLUME_KEY(153),
        @UiEvent(doc = "The ringer mode was toggled to silent")
        RINGER_MODE_SILENT(154),
        @UiEvent(doc = "The ringer mode was toggled to vibrate")
        RINGER_MODE_VIBRATE(155),
        @UiEvent(doc = "The ringer mode was toggled to normal")
        RINGER_MODE_NORMAL(156),
        @UiEvent(doc = "USB Overheat alarm was raised")
        USB_OVERHEAT_ALARM(160),
        @UiEvent(doc = "USB Overheat alarm was dismissed")
        USB_OVERHEAT_ALARM_DISMISSED(161);

        private final int mId;

        VolumeDialogEvent(int id) {
            mId = id;
        }

        public int getId() {
            return mId;
        }

        static VolumeDialogEvent fromIconState(int iconState) {
            switch (iconState) {
                case ICON_STATE_UNMUTE:
                    return VOLUME_DIALOG_UNMUTE_STREAM;
                case ICON_STATE_MUTE:
                    return VOLUME_DIALOG_MUTE_STREAM;
                case ICON_STATE_VIBRATE:
                    return VOLUME_DIALOG_TO_VIBRATE_STREAM;
                default:
                    return INVALID;
            }
        }

        static VolumeDialogEvent fromSliderLevel(int level) {
            return level == 0 ? VOLUME_DIALOG_SLIDER_TO_ZERO : VOLUME_DIALOG_SLIDER;
        }

        static VolumeDialogEvent fromKeyLevel(int level) {
            return level == 0 ? VOLUME_KEY_TO_ZERO : VOLUME_KEY;
        }

        static VolumeDialogEvent fromRingerMode(int ringerMode) {
            switch (ringerMode) {
                case AudioManager.RINGER_MODE_SILENT:
                    return RINGER_MODE_SILENT;
                case AudioManager.RINGER_MODE_VIBRATE:
                    return RINGER_MODE_VIBRATE;
                case AudioManager.RINGER_MODE_NORMAL:
                    return RINGER_MODE_NORMAL;
                default:
                    return INVALID;
            }
        }
    }

    @VisibleForTesting
    public enum ZenModeEvent implements UiEventLogger.UiEventEnum {
        INVALID(0),
        @UiEvent(doc = "Zen (do not disturb) mode was toggled to off")
        ZEN_MODE_OFF(156),
        @UiEvent(doc = "Zen (do not disturb) mode was toggled to important interruptions only")
        ZEN_MODE_IMPORTANT_ONLY(157),
        @UiEvent(doc = "Zen (do not disturb) mode was toggled to alarms only")
        ZEN_MODE_ALARMS_ONLY(158),
        @UiEvent(doc = "Zen (do not disturb) mode was toggled to block all interruptions")
        ZEN_MODE_NO_INTERRUPTIONS(159);

        private final int mId;
        ZenModeEvent(int id) {
            mId = id;
        }
        public int getId() {
            return mId;
        }

        static ZenModeEvent fromZenMode(int zenMode) {
            switch (zenMode) {
                case Global.ZEN_MODE_OFF: return ZEN_MODE_OFF;
                case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS: return ZEN_MODE_IMPORTANT_ONLY;
                case Global.ZEN_MODE_ALARMS: return ZEN_MODE_ALARMS_ONLY;
                case Global.ZEN_MODE_NO_INTERRUPTIONS: return ZEN_MODE_NO_INTERRUPTIONS;
                default: return INVALID;
            }
        }
    }

    public static Callback sCallback;
    @VisibleForTesting
    static MetricsLogger sLegacyLogger = new MetricsLogger();
    @VisibleForTesting
    static UiEventLogger sUiEventLogger = new UiEventLoggerImpl();

    /**
     * Logs an event to the system log and the event log.
     * Logs an event to the system log, to sCallback if present, and to the logEvent destinations.
     * @param tag One of the EVENT_* codes above.
     * @param list Any additional event-specific arguments, documented above.
     */
    public static void writeEvent(int tag, Object... list) {
        MetricsLogger logger = new MetricsLogger();
        final long time = System.currentTimeMillis();
        Log.i(TAG, logEvent(tag, list));
        if (sCallback != null) {
            sCallback.writeEvent(time, tag, list);
        }
    }

    /**
     * Logs an event to the event log and UiEvent (Westworld) logging. Compare writeEvent, which
     * adds more log destinations.
     * @param tag One of the EVENT_* codes above.
     * @param list Any additional event-specific arguments, documented above.
     * @return String a readable description of the event.  Begins "writeEvent <tag_description>"
     * if the tag is valid.
     */
    public static String logEvent(int tag, Object... list) {
        if (tag >= EVENT_TAGS.length) {
            return "";
        }
        final StringBuilder sb = new StringBuilder("writeEvent ").append(EVENT_TAGS[tag]);
        if (list != null && list.length > 0) {
        // Handle events without extra data
        if (list == null || list.length == 0) {
            if (tag == EVENT_SETTINGS_CLICK) {
                sLegacyLogger.action(MetricsEvent.ACTION_VOLUME_SETTINGS);
                sUiEventLogger.log(VolumeDialogEvent.VOLUME_DIALOG_SETTINGS_CLICK);
            }
            return sb.toString();
        }
        // Handle events with extra data. We've established list[0] exists.
        sb.append(" ");
        switch (tag) {
            case EVENT_SHOW_DIALOG:
                    logger.visible(MetricsEvent.VOLUME_DIALOG);
                    logger.histogram("volume_from_keyguard",
                            (Boolean) list[1] ? 1 : 0);
                    sb.append(SHOW_REASONS[(Integer) list[0]]).append(" keyguard=").append(list[1]);
                sLegacyLogger.visible(MetricsEvent.VOLUME_DIALOG);
                if (list.length > 1) {
                    final Integer reason = (Integer) list[0];
                    final Boolean keyguard = (Boolean) list[1];
                    sLegacyLogger.histogram("volume_from_keyguard", keyguard ? 1 : 0);
                    sUiEventLogger.log(VolumeDialogOpenEvent.fromReasons(reason));
                    sb.append(SHOW_REASONS[reason]).append(" keyguard=").append(keyguard);
                }
                break;
                case EVENT_EXPAND:
                    logger.visibility(MetricsEvent.VOLUME_DIALOG_DETAILS,
                            (Boolean) list[0]);
                    sb.append(list[0]);
            case EVENT_EXPAND: {
                final Boolean expand = (Boolean) list[0];
                sLegacyLogger.visibility(MetricsEvent.VOLUME_DIALOG_DETAILS, expand);
                sUiEventLogger.log(expand ? VolumeDialogEvent.VOLUME_DIALOG_EXPAND_DETAILS
                        : VolumeDialogEvent.VOLUME_DIALOG_COLLAPSE_DETAILS);
                sb.append(expand);
                break;
                case EVENT_DISMISS_DIALOG:
                    logger.hidden(MetricsEvent.VOLUME_DIALOG);
                    sb.append(DISMISS_REASONS[(Integer) list[0]]);
            }
            case EVENT_DISMISS_DIALOG: {
                sLegacyLogger.hidden(MetricsEvent.VOLUME_DIALOG);
                final Integer reason = (Integer) list[0];
                sUiEventLogger.log(VolumeDialogCloseEvent.fromReason(reason));
                sb.append(DISMISS_REASONS[reason]);
                break;
                case EVENT_ACTIVE_STREAM_CHANGED:
                    logger.action(MetricsEvent.ACTION_VOLUME_STREAM,
                            (Integer) list[0]);
                    sb.append(AudioSystem.streamToString((Integer) list[0]));
            }
            case EVENT_ACTIVE_STREAM_CHANGED: {
                final Integer stream = (Integer) list[0];
                sLegacyLogger.action(MetricsEvent.ACTION_VOLUME_STREAM, stream);
                sUiEventLogger.log(VolumeDialogEvent.VOLUME_DIALOG_ACTIVE_STREAM_CHANGED);
                sb.append(AudioSystem.streamToString(stream));
                break;
            }
            case EVENT_ICON_CLICK:
                    logger.action(MetricsEvent.ACTION_VOLUME_ICON,
                            (Integer) list[0]);
                    sb.append(AudioSystem.streamToString((Integer) list[0])).append(' ')
                            .append(iconStateToString((Integer) list[1]));
                if (list.length > 1) {
                    final Integer stream = (Integer) list[0];
                    sLegacyLogger.action(MetricsEvent.ACTION_VOLUME_ICON, stream);
                    final Integer iconState = (Integer) list[1];
                    sUiEventLogger.log(VolumeDialogEvent.fromIconState(iconState));
                    sb.append(AudioSystem.streamToString(stream)).append(' ')
                            .append(iconStateToString(iconState));
                }
                break;
                case EVENT_TOUCH_LEVEL_DONE:
                    logger.action(MetricsEvent.ACTION_VOLUME_SLIDER,
                            (Integer) list[1]);
            case EVENT_TOUCH_LEVEL_DONE: // (stream|int) (level|int)
                if (list.length > 1) {
                    final Integer level = (Integer) list[1];
                    sLegacyLogger.action(MetricsEvent.ACTION_VOLUME_SLIDER, level);
                    sUiEventLogger.log(VolumeDialogEvent.fromSliderLevel(level));
                }
                // fall through
            case EVENT_TOUCH_LEVEL_CHANGED:
            case EVENT_LEVEL_CHANGED:
                case EVENT_MUTE_CHANGED:
                    sb.append(AudioSystem.streamToString((Integer) list[0])).append(' ')
                            .append(list[1]);
                    break;
                case EVENT_KEY:
                    logger.action(MetricsEvent.ACTION_VOLUME_KEY,
                            (Integer) list[0]);
            case EVENT_MUTE_CHANGED:  // (stream|int) (level|int)
                if (list.length > 1) {
                    sb.append(AudioSystem.streamToString((Integer) list[0])).append(' ')
                            .append(list[1]);
                }
                break;
                case EVENT_RINGER_TOGGLE:
                    logger.action(MetricsEvent.ACTION_VOLUME_RINGER_TOGGLE, (Integer) list[0]);
            case EVENT_KEY: // (stream|int) (lastAudibleStreamVolume)
                if (list.length > 1) {
                    final Integer stream = (Integer) list[0];
                    sLegacyLogger.action(MetricsEvent.ACTION_VOLUME_KEY, stream);
                    final Integer level = (Integer) list[1];
                    sUiEventLogger.log(VolumeDialogEvent.fromKeyLevel(level));
                    sb.append(AudioSystem.streamToString(stream)).append(' ').append(level);
                }
                break;
                case EVENT_SETTINGS_CLICK:
                    logger.action(MetricsEvent.ACTION_VOLUME_SETTINGS);
            case EVENT_RINGER_TOGGLE: {
                final Integer ringerMode = (Integer) list[0];
                sLegacyLogger.action(MetricsEvent.ACTION_VOLUME_RINGER_TOGGLE, ringerMode);
                sUiEventLogger.log(VolumeDialogEvent.fromRingerMode(ringerMode));
                sb.append(ringerModeToString(ringerMode));
                break;
                case EVENT_EXTERNAL_RINGER_MODE_CHANGED:
                    logger.action(MetricsEvent.ACTION_RINGER_MODE,
                            (Integer) list[0]);
            }
            case EVENT_EXTERNAL_RINGER_MODE_CHANGED: {
                final Integer ringerMode = (Integer) list[0];
                sLegacyLogger.action(MetricsEvent.ACTION_RINGER_MODE, ringerMode);
            }
                // fall through
                case EVENT_INTERNAL_RINGER_MODE_CHANGED:
                    sb.append(ringerModeToString((Integer) list[0]));
            case EVENT_INTERNAL_RINGER_MODE_CHANGED: {
                final Integer ringerMode = (Integer) list[0];
                sb.append(ringerModeToString(ringerMode));
                break;
                case EVENT_ZEN_MODE_CHANGED:
                    sb.append(zenModeToString((Integer) list[0]));
            }
            case EVENT_ZEN_MODE_CHANGED: {
                final Integer zenMode = (Integer) list[0];
                sb.append(zenModeToString(zenMode));
                sUiEventLogger.log(ZenModeEvent.fromZenMode(zenMode));
                break;
                case EVENT_SUPPRESSOR_CHANGED:
            }
            case EVENT_SUPPRESSOR_CHANGED:  // (component|string) (name|string)
                if (list.length > 1) {
                    sb.append(list[0]).append(' ').append(list[1]);
                }
                break;
            case EVENT_SHOW_USB_OVERHEAT_ALARM:
                    logger.visible(MetricsEvent.POWER_OVERHEAT_ALARM);
                    logger.histogram("show_usb_overheat_alarm",
                            (Boolean) list[1] ? 1 : 0);
                    sb.append(SHOW_REASONS[(Integer) list[0]]).append(" keyguard=").append(list[1]);
                sLegacyLogger.visible(MetricsEvent.POWER_OVERHEAT_ALARM);
                sUiEventLogger.log(VolumeDialogEvent.USB_OVERHEAT_ALARM);
                if (list.length > 1) {
                    final Boolean keyguard = (Boolean) list[1];
                    sLegacyLogger.histogram("show_usb_overheat_alarm", keyguard ? 1 : 0);
                    final Integer reason = (Integer) list[0];
                    sb.append(SHOW_REASONS[reason]).append(" keyguard=").append(keyguard);
                }
                break;
            case EVENT_DISMISS_USB_OVERHEAT_ALARM:
                    logger.hidden(MetricsEvent.POWER_OVERHEAT_ALARM);
                    logger.histogram("dismiss_usb_overheat_alarm",
                            (Boolean) list[1] ? 1 : 0);
                    sb.append(DISMISS_REASONS[(Integer) list[0]])
                        .append(" keyguard=").append(list[1]);
                sLegacyLogger.hidden(MetricsEvent.POWER_OVERHEAT_ALARM);
                sUiEventLogger.log(VolumeDialogEvent.USB_OVERHEAT_ALARM_DISMISSED);
                if (list.length > 1) {
                    final Boolean keyguard = (Boolean) list[1];
                    sLegacyLogger.histogram("dismiss_usb_overheat_alarm", keyguard ? 1 : 0);
                    final Integer reason = (Integer) list[0];
                    sb.append(DISMISS_REASONS[reason])
                            .append(" keyguard=").append(keyguard);
                }
                break;
            default:
                sb.append(Arrays.asList(list));
                break;
        }
        }
        Log.i(TAG, sb.toString());
        if (sCallback != null) {
            sCallback.writeEvent(time, tag, list);
        }
        return sb.toString();
    }

    public static void writeState(long time, State state) {
+215 −0

File added.

Preview size limit exceeded, changes collapsed.