1 /* 2 * Copyright (C) 2023 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.accessibility 18 19 import com.android.internal.annotations.GuardedBy 20 import com.android.internal.logging.UiEvent 21 import com.android.internal.logging.UiEventLogger 22 import com.android.internal.logging.UiEventLogger.UiEventEnum 23 import com.android.systemui.util.time.SystemClock 24 import javax.inject.Inject 25 26 /** 27 * Handles logging UiEvent stats for simple UI interactions. 28 * 29 * See go/uievent 30 */ 31 class AccessibilityLogger 32 @Inject 33 constructor(private val uiEventLogger: UiEventLogger, private val clock: SystemClock) { 34 35 @GuardedBy("clock") private var lastTimeThrottledMs: Long = 0 36 @GuardedBy("clock") private var lastEventThrottled: UiEventEnum? = null 37 38 /** 39 * Logs the event, but any additional calls within the given delay window are ignored. The 40 * window resets every time a new event is received. i.e. it will only log one time until you 41 * wait at least [delayBeforeLoggingMs] before sending the next event. 42 * 43 * <p>Additionally, if a different type of event is passed in, the delay window for the previous 44 * one is forgotten. e.g. if you send two types of events interlaced all within the delay 45 * window, e.g. A->B->A within 1000ms, all three will be logged. 46 */ logThrottlednull47 @JvmOverloads fun logThrottled(event: UiEventEnum, delayBeforeLoggingMs: Int = 2000) { 48 synchronized(clock) { 49 val currentTimeMs = clock.elapsedRealtime() 50 val shouldThrottle = 51 event == lastEventThrottled && 52 currentTimeMs - lastTimeThrottledMs < delayBeforeLoggingMs 53 lastEventThrottled = event 54 lastTimeThrottledMs = currentTimeMs 55 if (shouldThrottle) { 56 return 57 } 58 } 59 log(event) 60 } 61 62 /** Logs the given event */ lognull63 fun log(event: UiEventEnum) { 64 uiEventLogger.log(event) 65 } 66 67 /** 68 * Logs the given event with an integer rank/position value. 69 * 70 * @param event the event to log 71 * @param position the rank or position value that the user interacted with in the UI 72 */ logWithPositionnull73 fun logWithPosition(event: UiEventEnum, position: Int) { 74 uiEventLogger.logWithPosition(event, /* uid= */ 0, /* packageName= */ null, position) 75 } 76 77 /** Events regarding interaction with the magnifier settings panel */ 78 enum class MagnificationSettingsEvent constructor(private val id: Int) : 79 UiEventEnum { 80 @UiEvent( 81 doc = 82 "Magnification settings panel opened. The selection rank is from which " + 83 "magnifier mode it was opened (fullscreen or window)" 84 ) 85 MAGNIFICATION_SETTINGS_PANEL_OPENED(1381), 86 87 @UiEvent(doc = "Magnification settings panel closed") 88 MAGNIFICATION_SETTINGS_PANEL_CLOSED(1382), 89 90 @UiEvent(doc = "Magnification settings panel edit size button clicked") 91 MAGNIFICATION_SETTINGS_SIZE_EDITING_ACTIVATED(1383), 92 93 @UiEvent(doc = "Magnification settings panel edit size save button clicked") 94 MAGNIFICATION_SETTINGS_SIZE_EDITING_DEACTIVATED(1384), 95 96 @UiEvent(doc = "Magnification settings panel zoom slider changed") 97 MAGNIFICATION_SETTINGS_ZOOM_SLIDER_CHANGED(1385), 98 99 @UiEvent( 100 doc = 101 "Magnification settings panel window size selected. The selection rank is " + 102 "which size was selected." 103 ) 104 MAGNIFICATION_SETTINGS_WINDOW_SIZE_SELECTED(1386); 105 getIdnull106 override fun getId(): Int = this.id 107 } 108 } 109